1

この奇妙な振る舞いを説明してもらえますか:

行がロックされているかどうかを教えてくれるこのストアドプロシージャがあります

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 行が返され、2 回目の実行では残りの 1 行だけが返されます。

しかし、ORDER BY句を追加すると

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 個のロックされた行を返し、2 番目のトランザクションは NO ROWS を返します。

何故ですか?

4

1 に答える 1

1

問題は、関数 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
于 2013-02-26T14:09:31.087 に答える