これまでに見たすべての本、トランザクションについての話は、いくつかのSQLステートメントが関係するシナリオを示しています。
しかし、単一のステートメントについてはどうですか?彼らはどのレベルの分離を持っていますか?それは規格のどこかに指定されていますか?それとも、RDBMSと分離レベルに依存していますか?
いくつか例を示します。
_UPDATE table SET value = value + 1 WHERE id = 1;
_
これは複合_read-update-write
_操作です。並列トランザクションはread
とwrite
操作の間の値を変更できますか?一部の本では、この操作はRDBMSのほとんどで(マルチスレッドプログラミングの意味で)アトミックであると述べています。
SELECT * FROM table t1 JOIN table t2 USING (id);
テーブルが非常に大きい場合(またはクエリに複雑なフィルタリング句がある場合)、ある分離レベルで、並列更新により_t1.*
_列と_t2.*
_列が異なる可能性がありますか?
SELECT * FROM table1 WHERE id IN (SELECT t_id FROM table2);
副選択が実行された後、_table1
_の一部のレコードが削除される可能性はありますか? (ここでは、_table2.t_id
_がカスケード削除で_table1.id
_を参照していると想定しています。)
CTE ...
取引の詳細をすべて説明する便利なマニュアルへのリンクも高く評価されています。
SQL Serverの場合:
しかし、単一のステートメントについてはどうですか?
SQL Serverには、4つのトランザクション分離レベルがあります(悲観的ロックモデル)。デフォルトのトランザクション分離レベルは_Read Committed
_で、ロックはステートメントレベルで行われます。同じデータを取得する2つのステートメントが内部にあり、そのトランザクションの途中(最初のステートメントの直後、2番目のステートメントが開始する前)のトランザクションがある場合、他のトランザクションが最初のトランザクションによって取得されたデータを変更し、次に最初のトランザクション1番目と2番目のステートメントで異なるデータを返します。
これは、反復不能読み取り問題として知られています。これは、トランザクション分離レベルを_REPEATABLE READ
_に上げることで解決できます。この場合、ロックはトランザクションレベルで(ステートメントレベルではなく)発生します。
UPDATE table SET value = value + 1 WHERE id = 1;
_並列トランザクションで値を変更できますか?
いいえ、できません。これは単一のステートメントであり、その間、変更中の行に排他ロックが設定されます。
他のトランザクションまたはステートメントは、更新ステートメントが完了するまでこれらの行を変更できません
SELECT * FROM table t1 JOIN table t2 USING (id);
分離レベルによっては、並列更新によりt1。*列とt2。*列が異なる可能性がありますか?
はい、共有ロックが適用されないため、_READ UNCOMMITED
_が可能です(または(NOLOCK)ヒントが指定されている場合)。他の分離レベルでは-いいえ、共有ロックはt1とt2の行に配置されており、その間、行は変更できません(他のトランザクションは排他ロックを取得できません)。
SELECT * FROM table1 WHERE id IN (SELECT t_id FROM table2)
副選択の実行後にtable1の一部のレコードが削除される可能性はありますか?
_READ UNCOMMITTED
_では可能です。より高い分離レベルでは-このステートメントの実行中、共有ロックはtable1とtable2の選択されたすべての行に配置され、他のトランザクションは選択するまでtable1とtable2の行を変更できないため(排他ロックを設定)ステートメントが完了し、共有ロックがtable1およびtable2から解放されました
ここでは、SQL Serverの分離レベルに関する詳細情報を読むことができます。 https://docs.Microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql? view = sql-server-ver15