2017-11-29 16 views
0

同じUPDATEクエリを次のように2回実行しようとしました。外部キー制約付きローの更新でロックする

トランザクションが初めてロックされていませんが、2番目のクエリの後に行ロックが表示されます。

スキーマ:

test=# \d t1 
       Table "public.t1" 
Column | Type | Collation | Nullable | Default 
--------+---------+-----------+----------+--------- 
i  | integer |   | not null | 
j  | integer |   |   | 
Indexes: 
    "t1_pkey" PRIMARY KEY, btree (i) 
Referenced by: 
    TABLE "t2" CONSTRAINT "t2_j_fkey" FOREIGN KEY (j) REFERENCES t1(i) 

test=# \d t2 
       Table "public.t2" 
Column | Type | Collation | Nullable | Default 
--------+---------+-----------+----------+--------- 
i  | integer |   | not null | 
j  | integer |   |   | 
k  | integer |   |   | 
Indexes: 
    "t2_pkey" PRIMARY KEY, btree (i) 
Foreign-key constraints: 
    "t2_j_fkey" FOREIGN KEY (j) REFERENCES t1(i) 

既存のデータ:

test=# SELECT * FROM t1 ORDER BY i; 
i | j 
---+--- 
1 | 1 
2 | 2 
(2 rows) 

test=# SELECT * FROM t2 ORDER BY i; 
i | j | k 
---+---+--- 
3 | 1 | 
4 | 2 | 
(2 rows) 

UPDATEクエリと行ロックのステータス:

test=# BEGIN; 
BEGIN 
test=# UPDATE t2 SET k = 123 WHERE i = 3; 
UPDATE 1 
test=# SELECT * FROM t1 AS t, pgrowlocks('t1') AS p WHERE p.locked_row = t.ctid; 
i | j | locked_row | locker | multi | xids | modes | pids 
---+---+------------+--------+-------+------+-------+------ 
(0 rows) 

test=# UPDATE t2 SET k = 123 WHERE i = 3; 
UPDATE 1 
test=# SELECT * FROM t1 AS t, pgrowlocks('t1') AS p WHERE p.locked_row = t.ctid; 
i | j | locked_row | locker | multi | xids |  modes  | pids 
---+---+------------+--------+-------+----------+-------------------+------ 
1 | 1 | (0,1)  | 107239 | f  | {107239} | {"For Key Share"} | {76} 
(1 row) 

test=# 

Postgresが唯一の二度目に行ロックを取得しようとしないのはなぜ?

ちなみに、クエリ更新列t2.jは、t1行の新しいロック(ForKeyShare)を一度に作成します。この動作は、t2.jに外部キー制約の参照t1.iがあるので意味があります。しかし、上記の質問はそうではないようです。

誰でもこのロックについて説明できますか?

PostgreSQLのバージョン:9.6.3

答えて

0

わかりました、私はそれを得ました。

http://blog.nordeus.com/dev-ops/postgresql-locking-revealed.htm

これはPostgresの中に存在する最適化です。ロックマネージャは、外部キーが変更されていない(更新クエリで言及されていないか、同じ値に設定されている)最初のクエリから把握できる場合、親テーブルをロックしません。しかし、それはマニュアルに記載されているように、それは動作します2番目のクエリに

MySQLは、外部キーロックについて賢明であるようだ(それはROW SHAREロックモードで親テーブルをロックし、SHAREモードの内の行を参照します)同じ理由UPDATEクエリはMySQLでこのようなロックを行いません。

+0

なぜROW SHAREロックが問題だと思いますか? –

+0

ロックの競合が原因で不要なロックのパフォーマンスが低下し、私の場合はデッドロックが発生しています。もちろん、あるトランザクションで同じ行にある複数のUPDATEがうまくいかず、明示的なロックを使用するとデッドロックの危険性を減らすことができます。私の場合、デッドロックはTPC-Cのパフォーマンステストが自分で作成されていないと起こりました。 PostgreSQLだけがこのように動作する理由を知りたかったのです。 – 38kun

+0

T1の行共有は、その行の更新(または選択)を妨げません。その行のDELETEのみを防止します。だから私はそれがどのようにデッドロックにつながるのか理解していない。プラスデッドロックは、データベース内の問題ではなく、_application_でのトランザクション処理の誤りの兆候です。しかし、推論や技術的な詳細を知りたければ、[postgresメーリングリスト](https://www.postgresql.org/list/pgsql-general/)でこれを尋ねてください。 –

関連する問題