明日のためにその1:トランザクション処理に依存しすぎない

最近いわゆる非RDBでちょいと苦労したので、この記事は楽しく読めた。一方で、この記事を勘違いして読み取って、やたらとロックかけまくるようなシステムを作り上げる人達が増えないことを願って、ちょいとメモ書きなどを。

DBの「トランザクション分離レベル」が必要な理由  (PostgreSQLで,ファントム・リードを防止すべきサンプル事例)

分離レベルがデフォルト(read comitted)のままだと,恐ろしい不具合が発生する。

この後簡単な例題があって「ね、ファントムリードって怖いでしょ」という話に進んでいるわけだ。でも考えてみよう。「ある瞬間に唐突に締めきって、その瞬間にお金を分配する」なんていう処理はあるのだろうか? 商売の世界なら「締め時間」があり、それ以前に受け付けたものなら処理の対象になる、というのが普通であろう。そして午後3時に締めて、そのコンマ数秒後に結果を出さなければならない、という商売も珍しいはずだ。

つまり記事の例題なら社員になった日時属性を持たせておき、分配日時に社員である人のみを対象として山分けすれば良い。分配日時から数分経過してから処理を走らせてやれば、トランザクション分離レベルの低い設定のPostgresはもちろん、非RDBのSimpleDBでも件の処理は問題なく走ることであろう。*1

「いやそうはいってもリアルタイムに在庫を更新・参照できないと困る」というシステムももちろんあろう。列車や飛行機の座席指定が重なってしまうのはあまりありがたい話ではない。記事にもあるように

上記では,「分離レベルがSERIALIZABLEであるべきケース」を取り上げた。
が,いつもSERIALIZABLEである必要はない。

むしろ,分離レベルを上げることによって,データ操作の信頼性は上がるものの,
ロックが多くなるので,後続の処理は「待たされがち」になる。
つまり,分離レベルを上げると,パフォーマンスは悪化する。

だから,アプリの特性や処理の特性ごとに,2つ(or 4つ)の分離レベルを使い分けるのが一番良い。
という事になる。


これが,本エントリの主題
『DBの「トランザクション分離レベル」が必要な理由』
に対する回答だ。

と、使い分けることが重要なんだけど、自分は「できるだけトランザクション処理に依存しない」思考を心がけている。ブツにもよるけど、非RDBでの実装に役立つこともあるし。

*1:RDBAmazon SimpleDBはレコード書込み後数秒はその内容を読めなかったり、削除後数秒間は読めちゃったりすることもある。頻繁ではないけど。