4

いくつかのIN句を含む SQL クエリがあります。クエリ プランのキャッシュを改善するために、テーブル値パラメーターを使用することにしました。これがサンプルWHERE ID IN (SELECT ID FROM @P1)です。@P1 は次の型の変数です:

CREATE TYPE [dbo].[Ids] AS TABLE(
    [ID] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)

しかし、一部のクエリが遅くなることに気付きました。クエリの例は次のとおりです。

select * from SomeTable s where ((s.SomeForeignId in (select id from @p1)) or s.SomeForeignId is null)

私のデータベースで2.1秒で実行されます。

そして古いクエリ:

select * from SomeTable s where ((s.SomeForeignId in (1,2,3.....)) or s.SomeForeignId is null)

1.8秒で実行します。

クエリプランの違いに気付きました。最初のクエリのプランは 2 つの部分 (null チェック用と in 句用) で構成され、連結が続きます。2番目の計画は単なるインデックスシークです。

パラメータ化されたクエリを改善して実行速度を上げる方法はありますか?

PS これは抽出されたクエリのサンプルにすぎません。このin (select id from @p1)部分に誤りがあるかどうかを知りたいです。

4

1 に答える 1

5

いくつかの提案:

  1. 使用しないでください。SELECT *実際に必要な列をリストするだけです

  2. スキーマ接頭辞を常に使用します

  3. EXISTSではなく使用しますIN(前者は短絡する可能性があるため):

    SELECT cols FROM dbo.SomeTable AS s 
      WHERE EXISTS (SELECT 1 FROM @p1 WHERE ID = s.SomeForeignId)
      OR SomeForeignId IS NULL;
    
  4. 上記は依然として連結で終わる可能性があります(これは本質的に a を意味します)が、を避けるためにUNION独自の記述を試みることができます:UNION ALLOR

    SELECT cols FROM dbo.SomeTable AS s 
      WHERE EXISTS (SELECT 1 FROM @p1 WHERE ID = s.SomeForeignId)
    UNION ALL
    SELECT cols FROM dbo.SomeTable
      WHERE SomeForeignId IS NULL;
    

私を悩ませているのは、既存のバリエーションのいずれかがほぼ 2 秒かかることです。SomeTable.SomeForeignId外部キー制約だけでなく、実際の非クラスター化インデックスにインデックスがあることを確認してください。あなたの質問では、これがシークするインデックスであることは明らかではありません。

于 2013-04-16T11:37:10.157 に答える