金宏 和實(かねひろ かずみ)

 富山県高岡市 株式会社イーザー副社長。昔は1月初旬に積雪がないと「いい正月やね。雪なーて」と富山弁であいさつしたものだが,現在は地球温暖化を目のあたりにするようで不気味だ。でも,会社まで公共交通機関はなく,雨やときおり雪が降るので車で通勤している。徒歩や自転車に変えなければと思うのだが,冬場はやはり億劫だ。

 「トランザクション処理は関連する複数の処理をまとめて,一つのユニットとして実行する処理方式です」──データベースの入門書にはたいていこんな風に書いてあります。

 説明用の最も多い図解が,図1のような銀行の口座間の振替処理ではないでしょうか。Aさんの口座から5万円出金した後で,何らかの原因でBさんの口座に入金することができなかったら,5万円が宙に浮いてしまいます。

図1●トランザクション処理は複数の処理をまとめる
図1●トランザクション処理は複数の処理をまとめる
  • トランザクションとして一つのユニットとして実行することで,更新処理をALL or Nothingの状態にできるので,中途半端な状態が発生しない
  • BEGIN TRANSACTIONで始めたトランザクション内の処理がすべて首尾良く実行されたら,コミット(COMMIT)でデータベースに反映させる。一つでもうまく実行できない処理があったら,ロールバック(ROLLBACK)ですべてに変更を元に戻す

 このようなトランザクション処理の説明はもちろん正しい説明です。筆者も書き出しはたいていこんな感じです。でも今回,考えていきたいのは「じゃあ,更新処理が途中でうまく行かないときはどんなとき?」ということです。Aさんの口座から5万円マイナスして,すぐにBさん口座に5万円プラスしようとしてできないのは実際にはどんなときでしょうか?

 ハードウエアが故障したとき,電源が落ちたとき,あるいはテロリストによる攻撃を受けたとき──でも,そんなときは,たとえトランザクション処理をしていたとしてもロールバックすることはできませんね。

 1台のPCにデータベース・サーバーをインストールして,きちんとテストされたアプリケーションを一人で実行している場合にはデータの矛盾は発生しにくいでしょう。PCがフリーズしたとか,ハードウエアが故障したといった場合ぐらいしか,データベースに不整合が起きることはないでしょう。

 問題は,複数のユーザーが同じ時間帯にたくさんの更新処理をかけてきたときに発生します。あるユーザーがレコードを読み込み,その値をもとに更新処理をしようとするときに,別のユーザーが同じ処理を実行する。そんな競合を避け,同時実行をコントロールするために役立つのがトランザクションなのです。

トランザクションの分離レベル

 トランザクションには分離レベルがあります。分離レベルを指定することで,複数のトランザクションがお互いに与える影響をコントロールすることができます。

◆ダーティ・リード(未コミット読み取り)

 他のトランザクションで更新されて,まだコミットされていないデータを読み取ってしまう。ロールバックされるとありえないデータを読み込んだことになる。

◆ファジー・リード(またはノンリピータブル・リード)

 他のトランザクションの更新前とコミット後のデータを読んでしまうことにより一度読み込んだデータを再読み込みすると結果が異なる。

◆ファントム・リード(幻影読み取り)

 他のトランザクションがデータの挿入,削除を行うとき,同じ検索条件で読んでいるのに,あったはずの行が消えたり,なかった行が現れたりする。

図2●三つの異常なリード(READ)

1. READ UNCOMMITTED

 READ UNCOMMITTED(リード・アンコミッテッド)は,最も分離性が低い分離レベルです。他のトランザクションがコミットしていないデータを読み込んでしまいます。図2のダーティ・リード,ファジー・リード,ファントム・リードすべてを許容します。

2. READ COMMITTED

 READ COMMITTED(リード・コミッテッド)は,2番目に分離性が低い分離レベルですが,未コミットのデータは読み取りません。具体的にはファジー・リード,ファントム・リードは許しますが,ダーティ・リードは抑止します。

3. REPEATABLE READ

 REPEATABLE READ(リピータブル・リード)を指定すると,あるトランザクションが参照したデータは,そのトランクションが終了するまで,他のトランザクションで変更することができなくなります。具体的にはダーティ・リード,ファジー・リードを抑止して,ファントム・リードだけを許可します。

4. SERIALIZABLE

 SERIALIZABLE(シリアライザブル)が最も分離性の高いレベルです。ダーティ・リード,ファジー・リード,ファントム・リードのいずれも抑止します。あるトランザクションが参照したデータを変更することができないだけでなく,参照に使用した条件に一致するデータを挿入することもできなくなるわけです。

図3●四つの分離レベル
図3●四つの分離レベル
[画像のクリックで拡大表示]

 この四つの分離レベルがANSI標準です。マイクロソフトのSQL Serverは,四種類の分離レベルをすべてサポートしています。シリアライザブルを使えば,最も安全なのですが,ロック待ちが多発したり,デッドロックに陥る可能性が増えます。

 逆に,分離レベルが最も低いリード・アンコミッテッドにすれば,パフォーマンスは最大になりますが,ダーティ・リード,ファジー・リード,ファントム・リードが発生してしまいます。安全性とパフォーマンスを秤(はかり)に掛けて,SQL Serverではリード・コミッテッドをデフォルトの分離レベルに設定しています。

 実際にトランザクションが必要な更新の例をあげて説明をします。