2013-02-25 51 views
1

能否請您給我解釋一下這種奇怪的行爲:PosgreSQL並選擇更新限制

我有這個存儲過程,它告訴我,如果一個行被鎖定

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行。

,但如果我添加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個鎖定行,和第二交易不返回行

這是爲什麼?

回答

1

問題是函數tg_availablega_is_unlocked確實鎖定了它檢查的行。如果沒有排序,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