web-dev-qa-db-ja.com

Postgres SELECT ... FOR UPDATE in functions

Postgres関数でSELECT…FOR UPDATE行レベルロックを使用することについて2つの質問があります。

  • 選択する列は重要ですか?ロックしてから更新する必要があるデータと関係がありますか?

    SELECT * FROM table WHERE x=y FOR UPDATE;
    

    SELECT 1 FROM table WHERE x=y FOR UPDATE;
    
  • データをどこかに保存せずに関数で選択を行うことはできないため、ダミー変数に保存します。これはハッキーに思えます。それは物事を行う正しい方法ですか?

私の機能は次のとおりです。

CREATE OR REPLACE FUNCTION update_message(v_1 INTEGER, v_timestamp INTEGER, v_version INTEGER)
RETURNS void AS $$
DECLARE
    v_timestamp_conv TIMESTAMP;
    dummy INTEGER;
BEGIN
    SELECT timestamp 'Epoch' + v_timestamp * interval '1 second' INTO v_timestamp_conv;
    SELECT 1 INTO dummy FROM my_table WHERE userid=v_1 LIMIT 1 FOR UPDATE;
    UPDATE my_table SET (timestamp) = (v_timestamp_conv) WHERE userid=v_1 AND version < v_version;
END;
$$  LANGUAGE plpgsql;
30
Dan Taylor

選択する列は重要ですか?

いいえ、それは問題ではありません。たとえ SELECT 1 FROM table WHERE ... FOR UPDATEを使用すると、クエリはwhere条件を満たすすべての行をロックします。

クエリが結合から行を取得し、結合に関係するすべてのテーブルの行をロックするのではなく、特定のテーブルの行のみをロックする場合、SELECT ... FOR UPDATE OF list-of-tablenames構文は便利です。
http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE


データをどこかに保存せずに関数で選択を行うことはできないため、ダミー変数に保存します。これはハッキーに思えます。それは物事を行う正しい方法ですか?

Pl/PgSqlでは、PERFORMコマンドを使用してクエリ結果を破棄します。
http://www.postgresql.org/docs/9.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT

の代わりに:

SELECT 1 INTO dummy FROM my_table WHERE userid=v_1 LIMIT 1 FOR UPDATE;

使用する:

PERFORM 1 FROM my_table WHERE userid=v_1 LIMIT 1 FOR UPDATE;
38
krokodilko