【PostgreSQL 11】デッドロックを発生させてみた。

デッドロックとは、2つ(もしくはそれ以上)のトランザクションにおいて、それぞれが、他方のトランザクションが必要とするロックを所持してしまうこと

公式ドキュメントを参考に開発環境でデッドロックを再現する。

まずはテーブルの作成する。

postgres=# -- accountsテーブルの作成
postgres=# CREATE TABLE accounts (acctnum int, balance int);
CREATE TABLE
postgres=#
postgres=# -- データの投入
postgres=# INSERT INTO accounts VALUES (11111, 100),(22222, 200);
INSERT 0 2

ターミナルを二つ立ち上げてそれぞれでトランザクションを開始する。
(便宜上トランザクションA,Bと呼称する)

postgres=# -- トランザクションA開始
postgres=# BEGIN;
BEGIN
postgres=# UPDATE accounts SET balance = balance + 100 WHERE acctnum = 11111;
UPDATE 1
postgres=# -- トランザクションB開始
postgres=# BEGIN;
BEGIN
postgres=# UPDATE accounts SET balance = balance + 100 WHERE acctnum = 22222;
UPDATE 1
postgres=# UPDATE accounts SET balance = balance - 100 WHERE acctnum = 11111;

トランザクションAでacctnum=11111の行レベルロックを獲得しているため
トランザクションBの二つ目のUPDATE分はロック開放待ちとなる。
試しにpg_locksシステムビューでロックの一覧を確認する。

postgres=# SELECT * FROM pg_locks;
   locktype    | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid  |       mode
| granted | fastpath
---------------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+------+------------------
+---------+----------
 relation      |    13938 |    11645 |      |       |            |               |         |       |          | 3/77493            | 6039 | AccessShareLock
| t       | t
 relation      |    13938 |    16718 |      |       |            |               |         |       |          | 3/77493            | 6039 | RowExclusiveLock
| t       | t
 virtualxid    |          |          |      |       | 3/77493    |               |         |       |          | 3/77493            | 6039 | ExclusiveLock
| t       | t
 relation      |    13938 |    16718 |      |       |            |               |         |       |          | 4/7470             | 6279 | RowExclusiveLock
| t       | t
 virtualxid    |          |          |      |       | 4/7470     |               |         |       |          | 4/7470             | 6279 | ExclusiveLock
| t       | t
 tuple         |    13938 |    16718 |    0 |     1 |            |               |         |       |          | 4/7470             | 6279 | ExclusiveLock
| t       | f
 transactionid |          |          |      |       |            |           995 |         |       |          | 4/7470             | 6279 | ShareLock
| f       | f
 transactionid |          |          |      |       |            |           995 |         |       |          | 3/77493            | 6039 | ExclusiveLock
| t       | f
 transactionid |          |          |      |       |            |           996 |         |       |          | 4/7470             | 6279 | ExclusiveLock
| t       | f
(9 rows)

このとき、トランザクションAでacctnum=22222の行レベルのロックを獲得しようとすると
デッドロックが発生する。

postgres=# UPDATE accounts SET balance = balance - 100 WHERE acctnum = 22222;
ERROR:  deadlock detected
DETAIL:  Process 6039 waits for ShareLock on transaction 996; blocked by process 6279.
Process 6279 waits for ShareLock on transaction 995; blocked by process 6039.
HINT:  See server log for query details.
CONTEXT:  while updating tuple (0,2) in relation "accounts"

ロック開放待ちとなっていたトランザクションBのUPDATEが実行される。

postgres=# UPDATE accounts SET balance = balance - 100 WHERE acctnum = 11111;
UPDATE 1

どちらのトランザクションがアボートされるかは予測できない模様。

(どちらのトランザクションをアボートするかを正確に予期するのは難しく、これに依存すべきではありません)。

www.postgresql.jp

『わたしとぼくのPL/pgSQL』の感想。

PL/pgSQLとは何ぞや?」

 

そんなあなた(僕)がPL/pgSQLで世界に挨拶するための本。

kindle unlimitedなら無料で読める。

サンプルコードを実際に動かしながら、だいたい数時間くらいで読み終わるボリュームでした。

 

Windows10における最適な自動化ツールを考える。

毎朝cloudwatchから.csv形式で出力したログを集計する業務を自動化するための最適な方法を考える。

集計業務の引継ぎも考えてなるべく環境構築は不要でありたい。

 

python

Microsoft Storeからインストールする必要があるが、

windowsターミナルからpythonもしくはpyコマンドで手軽に実行できる。

 

C#

Microsoftが開発しているためWindows標準搭載、つまり環境構築不要。

ただコンパイルして.exe形式に変換して実行する必要がある。

 

batファイル

なんか古臭いからやだ。でも環境構築不要で一番今のニーズに合ってる。

 

シェルスクリプト

WSLおよびubuntuをインストールする必要がある。

Windows ターミナルなら以下のコマンドで簡単にインストールできるらしい。

wsl --install

 

うーん。。。悩むな