web-dev-qa-db-ja.com

SQL Serverが自己参照FKカスケード削除にクラスター化インデックススキャンを使用する理由

私は私の問題が何であるかを示すことができるように例を作りました:

セットアップ:

CREATE TABLE [dbo].[Test](
    [TestId] [bigint] IDENTITY(1,1) NOT NULL,
    [ParentTestId] [bigint] NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ([TestId] ASC)
)
GO

ALTER TABLE [dbo].[Test]  WITH CHECK ADD  CONSTRAINT [FK_Test_ParentTest] 
      FOREIGN KEY([ParentTestId])
REFERENCES [dbo].[Test] ([TestId])
GO

ALTER TABLE [dbo].[Test] CHECK CONSTRAINT [FK_Test_ParentTest]
GO

DECLARE @iter INT
SET @iter = 1
WHILE @iter < 1000
BEGIN
    INSERT INTO dbo.Test ( ParentTestId )
    VALUES  ( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
    ( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
    ( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
    ( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
    ( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null )
    SET @iter = @iter + 1
END
go

これにより、自己参照テーブルが作成され、40,000を超える行が追加されます。

アクション:

DELETE FROM dbo.Test WHERE TestId = 200

次に、このテーブルから行を削除します。実際のクエリプランをオンにして上記のステートメントを実行すると、自己参照キーのクラスタ化インデックススキャンでコストの20%が使用されていることがわかります。

これはこのシナリオでは大したことではありませんが、私の実際のシナリオでは、大きなテーブルに2,500万行以上あります。

だから、私は2つの質問があります:

  1. インデックススキャンを実行する理由は?主キー/クラスター化インデックスの値があります。なぜインデックスシークを行わないのですか?
  2. インデックスシークを実行するにはどうすればよいですか?(行を削除するには約1分かかります)

編集:これは、SQL Serverが、削除中の行を他の行が参照しているかどうかを確認しようとしているためと考えられました。しかし、「外部キー制約を強制する」を「いいえ」に設定しましたが、それでもクラスター化インデックススキャンと同じコストがかかりました。

4
Vaccano

削除しようとしている行が既存の行の親ではないことを検証する必要があります。

ParentTestIdにインデックスがありません。

したがって、スキャンを実行する必要があります。

CREATE NONCLUSTERED INDEX ix ON  [dbo].[Test](ParentTestId)

その後、シークが表示されます。

ところで、この場合、スキャンの推定コストの20%は過小評価される可能性があります。

FK検証は左側の準結合の下にあり、SQL Serverは部分的なスキャンのみが必要であり、一致する行を見つけて削除が失敗するかのようにコストがかかります。

おそらく、実際に削除している行は成功する頻度が高いため、競合する行がないことを検証するためにフルスキャンが必要になります。

トレースフラグ4138を使用して行の目標をオフにする

DELETE FROM dbo.Test
WHERE  TestId = 200 
OPTION (querytraceon 4138 )

再計算されたプランでは、CIスキャンが20%ではなく100%で示されます(現在、フルスキャンが必要であると想定されているため)。

enter image description here

推定コストのこの違いは、欠落しているインデックスの提案が表示されるのに十分です。

ただし、この計画に示されているコストは、まだそれほど代表的なものではありません。合計が219%になっていることに気付くでしょう。

また、トレースフラグがある場合とない場合のクエリの全体的な計画コストは、0.0168268でも同じです。完全なCIスキャンは、実際には0.1523730.0485075 + 0.103866)で行う必要があります。

enter image description here

ただし、上限は元の計画コスト以下であるようです(全体の計画コストは上方調整されないため、パーセンテージも正しくありません)。

10
Martin Smith