親愛なる[あなたの名前はこちら]!
ああ、それを聞いてすみません!ちょっとした基本的なことから始めましょう。
あなたが実行しているものは、パラメータスニッフィングと呼ばれています
これは、ちょっとした奇妙な問題を解決する方法です。名前はすぐに舌から出てきます。リスのドイツ語のように。
そして、それは通常あなたの友人です。
クエリがサーバーにヒットすると、プランをコンパイルする必要があります。後で時間とリソースを節約するために、パラメータがコードを処理して返す推定行に基づいて実行計画がキャッシュされます。
これがうまくいかないことを想像する最も簡単な方法は、2つの一方的な母集団から物事を数える必要があるストアドプロシージャを想像することです。
例えば:
明らかに、そのコードの実行は別の実行よりも多くの作業を行う必要があり、まったく異なる量の作業を実行するクエリプランはまったく異なるように見えます。
私は何に反対ですか?
これは、見つける、テストする、修正するのが本当に難しい問題です。
- 一貫して発生しないため、見つけるのは難しい
- どのパラメーターが異なる計画を引き起こすかを知る必要があるため、テストするのは難しい
- クエリとインデックスのチューニングが必要になる場合があるため、修正が難しい
- クエリやインデックスを変更できない可能性があるため、修正が困難です
- クエリまたはインデックスを変更しても、まだ戻ってくる可能性があるため、修正するのは困難です
クイックフィックス
時には、必要なのは少し明確にするだけです。むしろ、あなたの計画キャッシュはそうします。
ストアドプロシージャの場合
実行してみてくださいEXEC sys.sp_recompile @objname = N'schema.procname'
。これにより、次回の実行時に新しい計画が再コンパイルされます。
これで修正されないもの:
これが保証しないもの:
- 再コンパイル後に実行される次のプロセスは、適切な計画を提供するパラメーターを使用します。
sp_recompile
テーブルまたはビューを指すこともできますが、そのテーブルまたはビューに触れるすべてのコードが再コンパイルされることに注意してください。これにより、問題が非常に難しくなる可能性があります。
パラメータ化されたクエリの場合
あなたの仕事はもう少し難しいです。SQLハンドルを追跡する必要があります。プランキャッシュ全体を解放する必要はありません。sp_recompile
テーブルまたはビューに対して使用するのと同じように、意図しない結果を引き起こす可能性があります(笑)。
このコマンドを理解する最も簡単な方法は、sp_BlitzWho *!を実行することです。キャッシュから単一のプランを削除するコマンドを持つ「fix parameter sniffing」という列があります。ただし、これには再コンパイルと同じ欠点があります。
これで修正されないもの:
これが保証しないもの:
- 再コンパイル後に実行される次のプロセスは、適切な計画を提供するパラメーターを使用します。
まだ助けが必要です!
次のものが必要になります。
- 可能であれば、適切なクエリプラン
- 悪いクエリプラン
- 使用されるパラメーター
- 問題のクエリ
- テーブルとインデックスの定義
クエリプランとクエリの取得
クエリが実行されている場合、sp_BlitzWho *またはsp_WhoIsActiveを使用して、現在実行中のクエリをキャプチャできます。
EXEC sp_BlitzWho;
EXEC sp_WhoIsActive @get_plans = 1;
クエリが現在実行されていない場合は、sp_BlitzCache * を使用して、プランキャッシュでクエリを確認できます。
SQL Server 2016以降を使用しており、クエリストアを有効にしている場合は、sp_BlitzQueryStore * を使用できます。
EXEC dbo.sp_BlitzCache @StoredProcName = 'Your Mom';
EXEC dbo.sp_BlitzQueryStore @StoredProcName = 'Your Mom';
これらは、ストアドプロシージャのキャッシュバージョンを追跡するのに役立ちます。パラメータ化されたコードだけの場合、検索はもう少し難しくなります。ただし、これは役立つ場合があります。
EXEC dbo.sp_BlitzCache @QueryFilter = 'statement';
これらのいずれからも、ほぼ同様の出力が表示されるはずです。繰り返しになりますが、クールな青いクリック列を招待するクエリプランはあなたの友人です。
プランを共有する最も簡単な方法は、Paste The Plan * を使用するか、XMLをpastebinにダンプすることです。それを取得するには、それらの魅力的な青いクリック可能な列のいずれかをクリックします。クエリプランが新しいSSMSタブに表示されます。
会社のコードとクエリの共有に不安がある場合は、Sentry Oneの無料のプランエクスプローラーツールを使用して、プランを匿名化できます。覚えておいてください、これは助けを得るのをより難しくします-匿名化されたコードは読み、理解するのがずっと難しくなります。
ここで説明したこれらのツールはすべて、クエリテキストを返す必要があります。ここで他に何もする必要はありません。
パラメータを取得するのはもう少し難しいです。Plan Explorerを使用している場合、下部にタブがあり、それらがすべて一覧表示されます。
sp_BlitzCache * を使用している場合、ストアドプロシージャの実行ステートメントを提供するクリック可能な列があります。
テーブルとインデックスの定義を取得する
SSMSを簡単に右クリックして、スクリプトを作成できます。
すべてを一度に取得したい場合、sp_BlitzIndex *は、テーブルに直接向けると役立ちます。
EXEC dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow2010',
@SchemaName = 'dbo',
@TableName = 'Users';
これにより、テーブル定義が(createステートメントとしてではなく)提供され、すべてのインデックスのステートメントが作成されます。
この情報を収集して質問に追加すると、人々に役立つ十分な情報が得られるか、正しい方向に導かれるはずです。
自分でやりたい!
まあ、クール。私はあなたのために幸せです。あなたは狂った人。
パラメータスニッフィングを「修正」すると考えられる方法はたくさんあります。
しかし、これらは実際にはさまざまな方法でパラメータスニッフィングを無効にします。それは彼らが問題を解決できないと言うことではなく、彼らは本当に根本的な原因に到達しないだけです。
根本的な原因に到達することは通常、ある種の困難だからです。これらの厄介な「計画品質の問題」を探す必要があります。
高速プランと低速プランから始めて、次のような違いを探します。
- 使用されるインデックス
- 注文に参加
- シリアルvsパラレル
また、コードをパラメータースニッフィングに敏感にするさまざまな演算子を探します。
- ルックアップ
- 並べ替え
- 結合タイプ
- メモリ許可(および拡張により、流出)
- スプール
シークvsスキャン、インデックスの断片化、その他の人が気を散らすものに夢中になりすぎないようにしてください。
通常、非常に基本的なインデックス作成の問題があります。コードを少し書き換える必要がある場合があります。
パラメータスニッフィングの詳細を知りたい場合:
あなたがこれを読んでいて、リンクや役に立つツールを見逃したと思うなら、コメントを残してください。これを最新の状態に保つために最善を尽くします。