スナップショット分離レベル(Snapshot)は、リードコミッテッド分離レベル(Read Committed)と同じロックの動作をします。
つまり、読み取りの操作時に、データに対して共有ロックをかけません。
スナップショットとリードコミッテッドの違うところは、反復読み取りの整合性です。
スナップショットでは、一度読み取ったデータは当該トランザクション中、ずっと同じ値で読み取ります。
■Read Committed分離レベル
タイミング | トランザクションA | トランザクションB |
---|---|---|
1 | SELECT →値:1 | SELECT →値:1 |
2 | UPDATE →値:2 | SELECT →値:1 |
3 | SELECT →値:2 | SELECT →値:2←反復読み取り時の不整合 |
■Snapshot分離レベル
タイミング | トランザクションA | トランザクションB |
---|---|---|
1 | SELECT →値:1 | SELECT →値:1 |
2 | UPDATE →値:2 | SELECT →値:1 |
3 | SELECT →値:2 | SELECT →値:1←Snapshot分離レベルによるトランザクション単位の一貫性 |
ただし、スナップショット分離レベルはトランザクション期間中ずっとバージョン情報を保持しなくてはならないため
tempdbのリソースをより多く消費します。
また、スナップショット分離レベルでは、更新の競合が発生した場合エラーとなります。
つまり、上記例ではタイミング3の時点で、
トランザクションBにおいて、トランザクションAが更新したデータを更新しようとしたときに
以下のようなエラーが発生することになります。
System.Data.SqlClient.SqlException: 更新の競合により、スナップショット分離トランザクションが中断しました。スナップショット分離を使用してデータベース 'KUAD_ST' のテーブル 'dbo.M194EmitNumber' に直接または間接的にアクセスし、別のトランザクションによって変更または削除された行を更新、削除、または挿入することはできません。トランザクションを再試行するか、更新/削除ステートメントの分離レベルを変更してください。 場所 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 場所 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 場所 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 場所 System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 場所 System.Data.SqlClient.SqlDataReader.HasMoreRows() 場所 System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout) 場所 System.Data.SqlClient.SqlDataReader.Read() 場所 System.Data.SqlClient.SqlCommand.CompleteExecuteScalar(SqlDataReader ds, Boolean returnSqlValue) 場所 System.Data.SqlClient.SqlCommand.ExecuteScalar()