web-dev-qa-db-ja.com

「ときどき」遅いクエリの診断に関するアドバイス

カバリングインデックスを介してインデックス付きビューから結果を返すストアドプロシージャがあります。通常、高速で実行されます(約10ミリ秒)。場合によっては最大8秒で実行されることもあります。

ランダム実行の例を次に示します(注:これは遅いものではありませんが、渡される値を除いてクエリテキストは同じです)。

_declare @p2 dbo.IdentityType
insert into @p2 values(5710955)
insert into @p2 values(5710896)
insert into @p2 values(5710678)
insert into @p2 values(5710871)
insert into @p2 values(5711103)
insert into @p2 values(6215197)
insert into @p2 values(5710780)

exec ListingSearch_ByLocationAndStatus @statusType=1,@locationIds=@p2
_

SPROCは次のとおりです。

_ALTER PROCEDURE [dbo].[ListingSearch_ByLocationAndStatus]
    @LocationIds IdentityType READONLY,
    @StatusType TINYINT
AS
BEGIN
    SET NOCOUNT ON;

    SELECT      -- lots of fields
    FROM        [dbo].[ListingSearchView][a] WITH (NOEXPAND)
    INNER JOIN  @LocationIds [b] ON [a].[LocationId] = [b].[Id]
    WHERE       [a].[StatusType] = @statusType
    OPTION (RECOMPILE);
_

(注:最近、いくつかのアドバイスの後にOPTION (RECOMPILE)ヒントを追加しましたが、役に立ちませんでした。

これがカバーするインデックスです(注:ビューにはListingIdにもクラスター化インデックスがあり、これは一意です)

_CREATE NONCLUSTERED INDEX [IX_ListingSearchView_ForAPI] ON [dbo].[ListingSearchView]
(
    [LocationId] ASC,
    [StatusType] ASC
)
INCLUDE ( -- all the fields in the query) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
_

Showplan XML統計を使用して、プロファイラートレースを配置しました。

これは遅いもの(6秒)と関連する計画です: enter image description here

私が期待するとおりに見え、クエリが高速の場合は同じ計画です。

これが役立つ場合は、計画のコストのかかる部分を拡大します。 enter image description here

これが役立つ場合のビュー/バッキングテーブルの完全なスキーマは次のとおりです。 https://Pastebin.com/wh1sRcbQ

ノート:

  • インデックスはデフラグされており、統計は最新です。
  • もともとクエリはビューに対してインラインでしたが、安定化を試みるためにSPROCに移動しました。助けていない。
  • WITH OPTION (RECOMPILE);ヒントを追加します(機能しなかったため、パラメーターをスニッフィングできませんか?)
  • システム内の他のクエリも実行が遅くなることがあり、それらの計画にも明らかな問題はありません。
  • ロックされている可能性がありますか?確認方法がわからない。

次に試してみたいアイデアはありますか?

ありがとう

20
RPM1984

OPTION (RECOMPILE)を使用することが、パラメーターの盗聴の可能性を排除する効果的な方法であるとは本当に思いません。

パラメータスニッフィングは、SQLが特定のクエリについて混乱し、新しいパラメータを検出したためにSQLが新しいと考えるときに発生します。新しい実行プランを生成するために余分な時間がかかるため、処理が遅くなります。

そのオプションが行うことは、SQLに毎回新しいプランを強制的に生成させることですが、これはほとんど同じことです。代わりに、このヒントを使用してデフォルトパラメータを追加することを検討してください。

OPTION(OPTIMIZE FOR(@LocationIds='xx',@StatusType='xx'))

デフォルトのパラメータを選択するときは、統計的に代表的なセットを使用してください。
これにより、毎回同じプランが使用され、パラメータの盗聴の可能性がなくなります。それを行って、それが役に立たなかったと判断したら、おそらくパラメータの盗聴を可能性として無視しても安全です。

2
Shooter McGavin

おそらく順序を強制しようとするので、おそらく常に小さなテーブル(変数)から始めます。でもそれはビューでトリッキーです...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    OPTION (FORCE ORDER);

または、それが一般にテーブル変数をビューに結合する方法である場合は、ループ結合を強制できます。これも順序を強制します...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER LOOP JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    --leaving this here so you don't get an annoying warning 
    OPTION (FORCE ORDER);
1
Jeremy Giaco

クエリエディターでストアプロシージャの名前を入力してから、ストアプロシージャを選択します。名前&次に「推定実行プランの表示」を選択するか、(Ctrl + L)をクリックします。この画像の下。

Image of Display Estimated Execution plan

実行プランはクエリエディターの下部にある[メッセージ]タブのすぐ隣に表示されます。次に、緑色の線で不足しているインデックスの詳細を示し、それを右クリックします。次に、新しいクエリが新しいタブで開き、INDEXを作成します。その後、クエリは高速に実行されます。

したがって、私はこのメソッドをクエリの診断に使用しました。また、使用できるクエリやメソッドがたくさんあります。

Execution plan with details

0
rks_dotnet