3. 改良の内容
●
簡潔に言うと
1. 新しい行ロックモードが導入された
? 今までは FOR SHARE と FOR UPDATE の2つ
? 今回新たに FOR KEY SHARE と
FOR NO KEY UPDATE が加わった
2. 外部キーでこの新しいロックモードを使うことで、競合
が減って性能向上となる
? 外部キーの参照テーブルへのINSERT時は、被参照テーブルの該
当キー保持列にFOR KEY SHAREが実施される
?
ユーザが被参照テーブルに対し、キーを変更しない更新処理を
行う場合に自動でFOR NO KEY UPDATEが使われる
? FOR KEY SHARE と FOR NO KEY UPDATEは競合しない!
4. 新しいロックモード
FOR UPDATE FOR NO KEY
UPDATE
FOR SHARE FOR KEY SHARE
FOR UPDATE
× × × ×
FOR NO KEY
UPDATE × × ×
FOR SHARE
× ×
FOR KEY
SHARE ×
FOR NO KEY UPDATE は キー(外部キーとしての被参照)列の更新
を行わない更新時に使われる。
FOR KEY SHARE は、弱いロックで、対象列のキー列が変更され
ないことだけを保証したい場合に使われる。
5. 分かりづらいので、昔を振り返りつつ
●
簡単な仕組みのおさらい
– PostgreSQL は外部キーをトリガで実現している
– 参照テーブル、被参照テーブルについて、
TRIGGER EACH ROWSを仕掛けておき、矛盾す
る更新処理は弾くようになっている
ORDER_ID ITEM_ID DELIVER
1 1 2012-01-01
2 2 2012-01-02
ITEM_ID NAME STOCK
1 ペン 60
2 紙 80
3 寒天 1000
INSERT INTO ORDER
VALUES (1, 4, now());
ITEM_ID の 4は無い!
RI_FKey_check_in
s
制約違反!
ORDERテーブル ITEMテーブル
6. 寄り道
● PostgreSQLで外部キーを設定すると自動的にトリ
ガが付きますが、どんなトリガなのかはシステムカ
タログやsrc/backend/utils/adt/ri_triggers.cを見ると
分かります。
=# SELECT proname, prosrc
FROM pg_proc p, pg_trigger t
WHERE p.oid = t.tgfoid AND t.tgrelid = '被参照テーブル'::regclass;
proname | prosrc
----------------------+----------------------
RI_FKey_noaction_del | RI_FKey_noaction_del
RI_FKey_noaction_upd | RI_FKey_noaction_upd
(2 rows)
=# SELECT proname , prosrc
FROM pg_proc p, pg_trigger t
WHERE p.oid = t.tgfoid AND t.tgrelid = '参照テーブル'::regclass;
proname | prosrc
-------------------+-------------------
RI_FKey_check_ins | RI_FKey_check_ins
RI_FKey_check_upd | RI_FKey_check_upd
(2 rows)