データベースアプリケーションのパフォーマンスにおける7つの大罪(続き)~ 第二の大罪 ( SAP SQL Anywhere )
この記事のオリジナルは、Glenn Paulley が sybase.com に2012年5月に掲載したものです。Glenn はこの中で、SQL Anywhere で利用可能な様々なオプションを使用した場合の並行性制御とその結果について語っています。
2011年に、私は「 データベースアプリケーションのパフォーマンスにおける7つの大罪」と題したブログ記事を書きました。そして、それに続く記事として、2011年4月に「データベースアプリケーションのパフォーマンスにおける7つの大罪(続き)~ 第一の大罪 」という題で、リレーショナルモデルにおける弱い型付けに関連した問題について説明しました。
この記事では、並行性制御の影響、特にREAD UNCOMMITTED
や READ COMMITTED といった
弱い標準SQL 分離レベルの使用を決定する場合のトレードオフについて説明したいと思います。
ブロックによる競合
SQL 標準の分離レベル [3] であるREAD UNCOMMITTED(確定していないデータまで読み取る)、
READ COMMITTED
(確定した最新データを常に読み取る)、REPEATABLE READ
(読み取り対象のデータを常に読み取る)、そしてSERIALIZABLE
(直列化可能)をサポートする多くの商用データベースシステムは、通常、並行トランザクションによる更新異常を避けるため、ローレベルで2 フェーズロック (2PL) を使用します。
分離レベルが異なると、読み取りの動きには影響がありますが、書き込みの動きに影響はありません。
トランザクションは、まず最初にローを修正する前にそのローの排他ロックを獲得しなければならず、これはトランザクションがCOMMIT
またはROLLBACK
を実行するまで保持されます。
そのため、別のトランザクションによるそのローへのさらなる修正を防ぐことができます。
これが、2PL のセマンティクスです。
そのため、本質的に直列実行を強制するアプリケーションを設計するのは簡単です。
私が以前書いた容量計画のホワイトペーパーの例1 が、典型的な直列実行の例です。
この例では、アプリケーションは新しい client が挿入されると以下のような SQL 文のセットを yield しながら、サロゲートキーを増やしていきます。
- UPDATE surrogate SET @x = next key, next key = next key + 1 WHERE object-type = ‘client’;
- INSERT INTO client VALUES(@x, …);
- COMMIT;
サロゲートテーブル内の ‘client’ ロー上の排他ローロックは、トランザクションの終了まで保たれるので、このロジックは、事実上、全 client 挿入の直列化を強制します。このロジックを1つの、あるいはほんの 2・3 のトランザクションでテストするだけでは、後にパフォーマンス問題を引き起こしかねません。
この直列化が問題になるのは、スケール時のみで、全てがそうでないとしても、デッドロックを除き、並行性制御の問題です。
ロック競合によって発生した問題はパフォーマンスに大きく関係しているため、直列化を最もシビアな形式の1つとして、ロック競合をテストするのは困難です。
また、通常追加の待ちスレッドのみ yield するので、アプリケーションの並行性の程度を増すことによって問題を解決するのは難しく、以前私のメンターであった Great-West Life社のGord Steindel 氏が言っていたように-全ての CPU が同じスピードで待つ-ので、問題があるところに追加の計算パワーを投入しても、問題解決は困難です。
なぜ低い分離レベルではいけないのか?
続きはこちら:データベースアプリケーションのパフォーマンスにおける7つの大罪(続き)~ 第二の大罪 (SAP SQL Anywhere)
SAPの SAP SQLAnywhere製品ページはこちら