web-dev-qa-db-ja.com

CTEクエリを使用したバックエンドテーブル/行ロック構造

この質問は、私が尋ねた以前の質問の延長です。 ユニオン使用時のテーブルロック

私たちが使用している同じクエリで、これらのUNIONSで使用されるさまざまなクエリがブロックされる原因となっているのはCTEクエリです。

例えば:

CREATE TABLE #TempTable (
    [Columns]
)

WITH CTE1 (Columns)
(
    Select [Columns] FROM [Tables] WHERE [WHERE-Condition]
),
CTE2 (Columns)
(
    Select [Columns] FROM [Tables] WHERE [WHERE-Condition]
),
CTE3 (Columns)
(
    Select [Columns] FROM [Tables] WHERE [WHERE-Condition]
),
CTE4 (Columns)
(
    Select [Columns] FROM [Tables] WHERE [WHERE-Condition]
),
CTE5 (Columns)
(
    Select [Columns] FROM [Tables] WHERE [WHERE-Condition]
),
CTE6 (Columns)
(
    Select [Columns] FROM [Tables] WHERE [WHERE-Condition]
),
CTE7 (Columns)
(
    Select [Columns] FROM [Tables] WHERE [WHERE-Condition]
)

INSERT INTO #TempTable
SELECT * FROM CTE1
UNION
SELECT * FROM CTE2
UNION
SELECT * FROM CTE3
UNION
SELECT * FROM CTE4
UNION
SELECT * FROM CTE5
UNION
SELECT * FROM CTE6 WHERE [Where-Condition]
UNION
SELECT * FROM CTE7

CTEクエリを使用しているため、この特定のシナリオ(および明示的なトランザクションが宣言されていない)を想定すると、物理テーブルのロック構造が変更されますか?

CTE1のSELECTUNIONの一部として終了しても、物理テーブルはまだロックされていますか、それともロックはまだ解放されていますか?

前の質問の回答に基づいて、UNIONのコンテキストで、さまざまなSELECTステートメントの1つに対するSELECTが完了すると、テーブルは次のようになるという印象を受けましたリリースされました。それは間違っていますか?

このトランザクションの分離レベルは変更していません。私が理解しているように、これはREAD_COMMITTED。質問は、2つのSELECTステートメントでまだ当てはまります。この機能がどのように機能するかを理解しようとしています。私が使用している特定のクエリは7を使用しています。これが、7を指定した唯一の理由です。

2
Kirk Saunders

いいえ、CTEのためにロックは変更されません。あなたが示したことは、非再帰的なCTEです。これらは、SQLステートメントにサブクエリを導入するもう1つの方法です。クエリ

with some_CTE as
(
  select < whatever > from < something >
)
select * from some_CTE;

意味的に同一

select * from
(
  select < whatever > from < something >
) as some_alias;

クエリオプティマイザーはステートメントを論理的に等価なものに自由に再配置できるので、これらの2つのステートメントは同じ実行プランになる可能性があります。 (CTEまたはメインクエリに多くの結合がある、またはCTEが何度も参照される非常に複雑なクエリの場合、実行プランは異なる場合がありますが、これは最適化であり、CTEの機能の基本的な特性ではありません。)

この段落は、ロックに関する主要なポイントに接していますが、知っておく価値があります。 「CTE1のSELECTが終了したとき」と言うと、必ずしもそのように機能するとは限りません。実行は、クエリの意味を満たす任意の方法で続行できますが、実行されたシーケンスに従う必要はありません。書かれた。実行順序が記述された順序とどのように異なるかについての例は、 here および here を参照してください。

主な質問については、「SELECTが完了するとテーブルが解放されるという印象を受けました。それは間違いですか?」 this Microsoftのページを紹介します。

READ COMMITTEDの動作は、READ_COMMITTED_SNAPSHOTデータベースオプションの設定によって異なります。

READ_COMMITTED_SNAPSHOTがOFF(デフォルト)に設定されている場合、データベースエンジンは共有ロックを使用して、現在のトランザクションが読み取り操作を実行している間、他のトランザクションが行を変更しないようにします。共有ロックは、他のトランザクションが完了するまで、他のトランザクションによって変更された行をステートメントが読み取ることもブロックします。共有ロックのタイプによって、いつ解放されるかが決まります。 次の行が処理される前に行ロックが解放されます。次のページが読み込まれるとページロックが解放され、ステートメントが終了するとテーブルロックが解放されます。

ここ は、よりよく説明できる別の説明です。どちらのソースも、ロックが解除されるときにロックの細分性(行、ページ、またはテーブル)が影響することを明らかにしています。システム構成やロックのエスカレーションなど、これに影響する要素はたくさんあります。

また、この例ではUNIONを使用しています。これにより、結果から重複が削除されます。あなたはかもしれませんがUNION ALLを使用して異なるロック動作を取得しますが、データによっては重複を残し、より多くの行を返す可能性があります。

3
Michael Green