著作一覧 |
ある程度の長さをもったトランザクションを、並行に分割することを考えている。
たとえば、ABCの3つのテーブルを順に更新する処理を考えてみる。
txstart - A read with lock - A update - B read with lock - B update - c read with lock - C update - txend
という流れ。
今、同時に3つのトランザクションが実行されるとする。
このとき、いずれのテーブルにおいてもキーの重複がなく、かつデータベースが行ロックをサポートしていれば、この3つのトランザクションは並行して実行できる。
しかし、キーが重複していたら、Tx1−Tx2−Tx3と完全に直列化されることになる。
もし、Aの更新、Bの更新、Cの更新がお互いに独立しているのであれば、Aの読み書き、Bの読み書き、Cの読み書きを並行して実行できる。このとき元は1つのトランザクションだが、3つのトランザクションが必要となる。
同時にTx1,Tx2,Tx3が動くのであるから、最初の時点で9つのトランザクションが開始される。A,B,Cの各キーはすべてのトランザクションで重複しているが、直列化するのは、各テーブルのみですむ。つまり、Tx1(A)-Tx2(A)-Tx3(A)と、Tx1(B)-Tx2(B)-Tx3(B)……で、これは、最初の状態よりは全体に必要な時間は1/テーブル数の時間で良い。
このようにしたとき、元の方法より、プログラム的に難しくなるとしたら、それは最後にすべてのテーブルの更新状態を調べ、コミットするかロールバックするかを判断するところだ。コネクションの数が1つのトランザクションの並行数分確保できない場合も難しくなる。AとBのコネクションはあり、Cのコネクションがなければ、AとBを先行し、Cを待つというわけにはおそらくいかない。Cを待つ間、残りの2つを占有することになり、もしそこで実行してしまうと、Cの待ちによって終了処理ができず、可能性としては、それによってAまたはBでデッドロックを引き起こしかねない。
並行実行するとデッドロックの可能性が高まる。
Tx1のAとBは先に動作できて、しかしCはできず、Tx2のCが先に動作してAとBで待つ場合にありえる。
そう考えていくと一連の処理ならば直列して実行するモデルは堅いことがわかる。
おかしいな。なんかうまくいきそうに思えたのだが。もっと考えることにする。
……、ばらすのなら、完全にばらすしかないということか。待ち合わせしてコミットするのではなく、各テーブル単位でコミットする。ロールバック時は、トランザクションのロールバックではなく、補償更新によって行う。……面倒だな。
ジェズイットを見習え |