PostgreSQL并选择更新限制

PostgreSQL并选择更新限制,postgresql,transactions,locking,Postgresql,Transactions,Locking,你能给我解释一下这种奇怪的行为吗: 我有一个存储过程,它告诉我一行是否被锁定 CREATE OR REPLACE FUNCTION tg_availablega_is_unlocked(availablega_id integer) RETURNS boolean AS $BODY$ DECLARE is_locked boolean = FALSE; BEGIN BEGIN PERFORM id FROM tg_availablega WHERE id = avai

你能给我解释一下这种奇怪的行为吗:

我有一个存储过程,它告诉我一行是否被锁定

CREATE OR REPLACE FUNCTION tg_availablega_is_unlocked(availablega_id integer)
  RETURNS boolean AS
$BODY$
DECLARE
  is_locked     boolean = FALSE;
BEGIN
  BEGIN
    PERFORM id FROM tg_availablega WHERE id = availablega_id
    FOR UPDATE NOWAIT;
  EXCEPTION 
    WHEN lock_not_available THEN
            is_locked := TRUE;
  END;
  RETURN not is_locked;
END;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
如果我启动事务并执行此操作:

SELECT "tg_availablega"."id",
       "tg_availablega"."isactive",
       "tg_availablega"."schedule",
       "tg_availablega"."zone_tg_id"
FROM "tg_availablega"
WHERE (tg_availablega_is_unlocked("tg_availablega"."id")
       AND "tg_availablega"."zone_tg_id" = 1
       AND "tg_availablega"."isactive" = TRUE
       AND "tg_availablega"."schedule" = 20)
LIMIT 100
FOR
UPDATE;
它锁定并返回100行。如果我在其他事务中同时执行相同的操作,它将锁定并返回不同的100行。如果行总数为101,则第一次执行返回100行,第二次执行只返回剩余的1行

但是如果我加上ORDERBY条款

SELECT "tg_availablega"."id",
       "tg_availablega"."isactive",
       "tg_availablega"."schedule",
       "tg_availablega"."zone_tg_id"
FROM "tg_availablega"
WHERE (tg_availablega_is_unlocked("tg_availablega"."id")
       AND "tg_availablega"."zone_tg_id" = 1
       AND "tg_availablega"."isactive" = TRUE
       AND "tg_availablega"."schedule" = 20)
***ORDER BY "tg_availablega"."id"***
LIMIT 100
FOR
UPDATE;
然后,第一个事务返回100个锁定行,第二个事务不返回任何行


为什么会这样?

问题在于函数tg\u availablega\u is\u unlocked会锁定它检查的行。没有order by,Postgres不会访问所有行,因此不会对所有行调用该函数。我想你的意思是:

select * from (
SELECT "tg_availablega"."id",
   "tg_availablega"."isactive",
   "tg_availablega"."schedule",
   "tg_availablega"."zone_tg_id"
FROM "tg_availablega"
 WHERE "tg_availablega"."zone_tg_id" = 1
   AND "tg_availablega"."isactive" = TRUE
   AND "tg_availablega"."schedule" = 20)
ORDER BY "tg_availablega"."id"
) a
where tg_availablega_is_unlocked(id)
limit 100

问题是函数tg_availablega_is_unlocked会锁定它检查的行。没有order by,Postgres不会访问所有行,因此不会对所有行调用该函数。我想你的意思是:

select * from (
SELECT "tg_availablega"."id",
   "tg_availablega"."isactive",
   "tg_availablega"."schedule",
   "tg_availablega"."zone_tg_id"
FROM "tg_availablega"
 WHERE "tg_availablega"."zone_tg_id" = 1
   AND "tg_availablega"."isactive" = TRUE
   AND "tg_availablega"."schedule" = 20)
ORDER BY "tg_availablega"."id"
) a
where tg_availablega_is_unlocked(id)
limit 100