我让同一应用程序的多个进程彼此同时运行.这些过程中的每一个都执行一些计算.

我有一个"测试"表,如下所示:

 id | a | b |      c
----+---+---+-------------
 1  | a | b | Helloooo!!!
 2  | a | b | Helloooo...
 3  | c | d | World!!!
 4  | c | d | World...

每个进程都需要从表"test"中检索组中的第一行(GROUP BY列"a"和"b"),以便对其执行一些计算,但是一个进程不应该能够 Select 已经被另一个进程捕获的行.例如:

 id | a | b |      c
----+---+---+-------------
 1  | a | b | Helloooo!!!                  <------ Captured by process #1 and it won't have been available until the transaction is finished by process #1.
 2  | a | b | Helloooo...                  <------ Unavailable.
 3  | c | d | World!!!                     <------ Should be captured by concurrent process #2.
 4  | c | d | World...                     <------ Unavailable.

没有行级锁的我的SQL查询:

WITH t AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY a, b ORDER BY id ASC) AS rn
           FROM tests)
SELECT *
FROM t
WHERE rn = 1;

我试着这样做:

WITH groups AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY a, b ORDER BY id ASC) AS rn FROM tests)
SELECT * FROM (SELECT * FROM groups WHERE rn = 1) subquery FOR UPDATE SKIP LOCKED LIMIT 1;

但这两个流程检索相同的行(事务打开而不提交):

Process #1

  • 进程#1.

Process #2

  • 进程#2.

推荐答案

select...for update针对的是由CTE产生的临时表,而不是直接指向tests表的临时表,从而错置了锁.如果您改为使用CTE join来筛选您直接从锁定查询中锁定的实际表中的记录,则它将如预期的那样锁定tests个表:

BEGIN TRANSACTION;

WITH groups AS (
    SELECT  id, 
            ROW_NUMBER() OVER w1 AS rn 
    FROM tests
    window w1 as (PARTITION BY a, b ORDER BY id ASC))
SELECT * 
FROM tests inner join groups using (id) WHERE groups.rn = 1
FOR UPDATE SKIP LOCKED LIMIT 1;

如果FOR UPDATE在直接指向tests的CTE中,那么按照您所做的方式组织查询就可以了,但窗口函数的存在阻止了这一点,每当您try 直接或通过嵌套在子查询中组合这些查询时,就会弹出错误FOR UPDATE is not allowed with window functions.

Sql相关问答推荐

如何在一个范围内进行分组.""范围值在范围表中定义

使用Mac日志(log)时间找出SQL中的好小时和坏小时

Django将字符串筛选为整数?

删除事务中的本地临时表

如何在SQL中更新Json字符串

直接加法(1+1)与聚合函数SUM(1+1)的区别是什么

将计算列设置为持久化的目的是什么?

如何找到一个组合的两个列,这是不是在其他表在ORACLE SQL?

每个学校 Select N个最新的行,但跳过同一学生的重复行

如何使用Clickhouse的COUNT聚合返回所有列,但GROUP BY是这些列的子集

每个分组最多 Select 最后 2 个值并并排显示它们

如何在android房间中进行多个加入

当 2 列具有静态值并且第 3 列使用运算符 IN 时,对 PostgreSQL 和 3 列上的复杂索引的最佳查询

如何显示最常引用条目的详细信息

如何 Select 一列具有最小值而另一列具有给定值的记录?

如何获得上个月和下个月之间的销售额差异

Oracle SQL 从多个条件中 Select 但具有相同的 id

As400 (IBM i) SQL 表 QSYS2.SYSTABLES 上的元数据

以 15 分钟为间隔的使用情况SQL 查询

连续日期的SQL