Oracleでは、リードロックを取得しません。一方、DB2では、システム側で常にリードロックを取得します。デフォルトでは、ロックがかかるタイミングは、カーソルが行の上にある間です(図3)。
Oracleで更新を前提としたデータの読み取りを行う場合には、ユーザーが明示的に行ロックを取得するために、FOR UPDATE句を用います。これによって、トランザクション終了まで検索結果行にロックをかけ、ほかのトランザクションからの更新を防ぎます。
SELECT * FROM TABLE FOR UPDATE |
リスト1 OracleのFOR UPDATE句 |
一方、DB2では、デフォルトのリードロックだけではほかのトランザクションからの更新を禁止するには十分ではありません。そこで、分離レベルを「繰返し可能読み取り」もしくは「直列可能」に変更する必要があります。これによって、検索結果行にはCOMMITあるいはROLLBACK時までロックをかけ、ほかのトランザクションからの更新を防ぎます。
排他制御が必要な場面でその都度、個々のSQL文にWITH句を用いて分離レベルを指定してください。例えば、上図3の場合は、以下のSQL文をカーソルオープン前に発行することで、レコードA〜Dは、COMMITあるいはROLLBACK時までロックされた状態になります。
SELECT * FROM TABLE FOR UPDATE WITH
RS |
リスト2 DB2のWITH RS句 |
WITH句に付いているRSとは、ANSI/ISO標準トランザクション分離レベルでいう「繰り返し可能読み取り」分離レベルのことです。「直列可能」分離レベル(FOR UPDATE WITH RR)の場合、トランザクションが読み取ったレコードすべてに対してロックを取得するため、「繰り返し可能読み取り」分離レベルよりも、多くのロックを取得します。そのため「直列可能」分離レベルは、同時実行性が低下します。
OracleとDB2では、ロック待機への対処も異なります。ロック待機をせず、すぐに制御を戻す場合、Oracleでは、「SELECT〜FOR UPDATE」に「NOWAIT」オプションを指定します。一方、DB2では「NOWAIT」オプションに対応する機能をサポートしていません。DB2ではロック待機する時間を「LOCKTIMEOUT(単位:秒)」パラメータで指定し、ロック待機時間がLOCKTIMEOUTに達した場合、ロック待機しているトランザクションがロールバックされます(図4)。
DB2で、Oracleの「NOWAIT」オプションと同じ振る舞いを実現させるためには、LOCKTIMEOUTを0秒に設定します。このパラメータはデータベース単位の設定であり、すべてのトランザクションに一律に影響するため注意が必要です。実際のオペレーションを基にしたベンチマークや、アプリケーションの仕様を検討したうえで、このパラメータをチューニングしてください。例えば、10秒でロック・タイムアウトさせるように変更するコマンドは以下のようになります。
db2 UPDATE DB CFG FOR dbname USING LOCKTIMEOUT
10 |
リスト3 DB2でロック・タイムアウトを10秒に設定 |
また、タイムアウト発生時、リトライすることにより、エラーになった処理が問題なく実行される場合は、リターン・コードを利用して、アプリケーションにリトライ・ロジックを組み込む方法もあります。その際には、トランザクションがデータベース・マネージャによってロールバックされないよう、レジストリ変数でDB2LOCK_TO_RB=STATEMENTを指定しておく必要があります。ちなみに、データベース・マネージャによって、ロールバックされた場合は、「SQL0911N」のリターン・コードですが、STATEMENTを指定すると、「SQL0913N」が返されます。
なお、LOCKTIMEOUTは、デフォルトは「-1」で、ロック・タイムアウトを検出せず、永遠に解放を待ち続ける設定となっていますが、同時実行性の低下、デッド・ロックの発生につながりますので、必ずチューニングするようにしてください。
ここではOracleとの比較という話から外れますが、DB2で発生し得るロック・エスカレーションについて説明します。ロック・エスカレーションとは、1つのアプリケーションが多量の行ロックでロック用メモリ領域を占有することを防ごうとする働きで、一種の縮退運転の機能です。多数の行ロックを1つの表ロックに代えてロックの量を一挙に減らします。ロック用メモリ領域の大きさは、「LOCKLIST」(データベース構成パラメータ)により決定します。この領域の大きさ以上にロック情報が格納されるか、あるいは、単一アプリケーションが「MAXLOCKS」(データベース構成パラメータ)以上の割合でLOCKLISTを使用した場合に、ロック・エスカレーションが発生します(図5)。
しかし、ロック・エスカレーションは、アプリケーションの並行性に影響します。例えば、アプリケーションがロック・エスカレーションの発生によって、ある表の共用ロックを保持した場合、ほかのアプリケーションはその表内の行の更新はできなくなります。同様に、アプリケーションが表の排他ロックを保持した場合、ほかのアプリケーションはその表内の行の読み取りや更新ができません。
そこで、通常DB2のアプリケーション設計としては、ロック・エスカレーションを発生させないようにLOCKLISTとMAXLOCKSのパラメータをチューニングします。チューニングする際には、その使用環境でどれだけLOCKLISTが使われているかをモニタリングし、最適値を導き出します。LOCKLISTとMAXLOCKSのデフォルト値は非常に小さいので、必ず大きくする必要があると考えるべきでしょう。
今回は、OracleとDB2の「分離レベルとロッキング・メカニズム」の違い、およびそれによる両者の振る舞いの違いを解説しました。これらの違いは、あくまでも各ベンダの設計思想の違いです。決して、どちらが優れているというわけではありません。開発者がロッキング・メカニズムの差異を理解することは、最終的には、ユーザーに優しく実用的なシステムを構築することにつながります。今回の内容を参考に、それぞれのRDBMSの癖を理解して、そのRDBMSの性能をうまく引き出してください。
次回は、OracleとSQL Serverのパフォーマンス・チューニング方法の比較について同様に解説します。
アクセンチュアから生まれた、企業改革のためのシステム開発を手掛けるエンジニア集団。安間裕が代表取締役社長を務める。阿尾操はOracleとDB2に精通し、最近は、Seasar2がお気に入りのアナリスト・プログラマー。
Copyright © ITmedia, Inc. All Rights Reserved.