QA@IT

スナップショット分離レベルは“結構特殊”?

8422 PV

先日「2014/09/05 21:44 スナップショット分離でエラー」の質問で、
SQLSERVER 2005以降の、スナップショット分離レベルは“結構特殊な状況で使う”
と回答をいただきました。

しかし、どうも解せません。
READ_COMMITTED_SNAPSHOTオプションをONにするだけでは、行バージョン管理が
ONになるだけで、1つSELECT文の中で「スナップショットの古い内容をいったん読んだら、
最後まで古い内容を読む」というスナップショット分離レベルの特徴は無く、

たとえば、
有るトランザクション(Aテーブルに1行、Bテーブルに1行追加)という処理と
有るSELECT(AテーブルとBテーブルをJOINで読む)という処理があった場合、

READ_COMMITTED_SNAPSHOTオプションをONにするだけでは、たまたまSELECT中の
Aテーブル検索後、Bテーブル検索前に、運悪くあるトランザクションのコミットが
合った場合、Aテーブルは古く、Bテーブルは新しい内容を読んでしまいます。

スナップショット分離レベル
(conn.setTransactionIsolation(
  com.microsoft.sqlserver.jdbc.SQLServerConnection.TRANSACTION_SNAPSHOT);)
ならばそれは無くなります。

こちらの方が絶対いいと思います。また、READ_COMMITTED_SNAPSHOTオプションをON
がOracle相当だとしたら、上記(「Aテーブルは古く、Bテーブルは新しい内容を読んでしまう」)
がOracleで年に1回とか起こる、本当に訳の解らない値の不合致
(結局要観察で終わらせるより他無い)もそれが原因かとも疑いたくもなります。

本当に「スナップショット分離レベルは“結構特殊”」なのでしょうか?

回答

そもそもステートメントレベルの一貫性はSQL ServerでもOracleでも確保されていますので、1クエリ内のテーブルアクセスで矛盾が発生することはありません。
しかし複数クエリになると一貫性は保たれなくなります。

複数クエリ間で一貫性を保つ必要があるなら、もっと高いトランザクションレベルを使用するなり、SNAPSHOT分離レベルなりを使う必要があります。
特殊な場合というのはこっちの話です。
※特殊というか、デフォルト的に常に使うようなものではなく、必要な場合に明示的に使うもの、という感覚です。

Oracleの場合も同様です。

そもそも何も弊害がなければ単純に高い一貫性を使うのがいいですが、実際には高い一貫性=同時実行性の低下、パフォーマンスの低下につながりますので、バランスを取って必要に応じて使い分けるわけです。

編集 履歴 (1)
  • 本当にステートメントレベルの一貫性を、READ_COMMITTED_SNAPSHOTオプションをONのみで実現出来ているのでしょうか?ならその時点で必要十分で、2008R2以降に出来た、SNAPSHOT分離レベルがあまりにいらない子になりすぎると思います。
    Oracleはどうか知りませんが、SQLSで、SNAPSHOT分離レベル以前では、ステートメントレベルの一貫性は有ったのでしょうか?
    -
  • いや、だから結構特殊だと言ってるんです。
    本当に実現できてるのか?というのは、何か疑わしい理由があるんでしょうか?
    全部探せば見つかる資料に書かれてることです。
    もう見たと思いますが。

    ステートメント内では、ステートメント発行時のトランザクションシーケンス番号に基づいて一貫したスナップショットが使用されます。
    -
  • 「トランザクションシーケンス番号に基づいて一貫したスナップショットが使用」だとすると、READ_COMMITTED_SNAPSHOTオプションをONのみの機能を逸脱しています。1ステートメントの内部的には、スナップショット分離(シリアライザブル)に自動的に昇格するという事でしょうか? -
  • READ_COMMITTED_SNAPSHOTをONのみの機能を逸脱ってどういう意味で言ってるんです?
    READ_COMMITTED_SNAPSHOTはSQL Serverが実装している機能の名前であってその仕組みを決めているのもSQL Serverです。
    機能を逸脱の意味が分からないんですが…
    -
  • ステートメントレベルでの一貫性があることはあちこちに書かれてますし、それを実現するにはそういう仕組みが必要であろうことは分かってるんですよね?
    ドキュメントが間違っていると言いたいのでしょうか?
    -
  • READ_COMMITTED_SNAPSHOTの動作は、例えば
    http://technet.microsoft.com/ja-jp/library/ms189050.aspx
    に明記されてる話で、否定されてもそれ以上言うべき事はありません。
    -
  • なんとなく言いたいことが分かりました。
    1ステートメント内ではスナップショットのように動きますが、別にそれは昇格しているとは言わないでしょうし、READ_COMMITTED_SNAPSHOTの機能を逸脱しているわけでもないでしょう。
    -

まずはこちらのドキュメントが参考になると思います。

http://technet.microsoft.com/ja-jp/sqlserver/gg639075.aspx

既に参照済みでしたら無視してください。

編集 履歴 (0)
  • 有り難うございました。本当に本当に助かりました。
    しかしそうすると、1ステートメントの内部的には、スナップショット分離(シリアライザブル)に自動的に昇格するという事でしょうか?
    1ステートメントと言っても、同じテーブルを1なめで終わらないJOINを含むSQL文だって有るでしょうし。
    -
  • なぜ自動的に昇格すると思われたのか、その行間は読めませんでしたが、提示したドキュメントに「READ_COMMITTED_SNAPSHOT は、Oracle でのデフォルトの動作とほぼ同じであり、ステートメント発行時点での正しいデータを参照できることを保証します (ステートメント レベルの読み取り一貫性を実現)。」とあります。 -
  • すいませんでした。半可通でした。でも、この文書だけだと、素人考えでそう考えてもおかしくないと思いますが。。。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。