クエリが昨日よりも突然遅くなるのはなぜですか?


76

[挨拶]

(チェックしてください)

[ ] Well trained professional, [ ] Casual reader, [ ] Hapless wanderer,

私は持っています(該当するものすべてをチェックしてください)

[ ] query [ ] stored procedure [ ] database thing maybe  

正常に実行されていた(該当する場合)

[ ] yesterday [ ] in recent memory [ ] at some point 

しかし、今は突然遅くなっています。

既にブロックされていないこと、および長期にわたるメンテナンスタスク、レポート、またはその他の帯域外プロセスの犠牲になっていないことを確認しました。

問題は何ですか、どうすればよいですか、また、ヘルプを得るためにどのような情報を提供できますか?

[*Insert appropriate closing remarks*]

回答:


88

親愛なる[あなたの名前はこちら]!

ああ、それを聞いてすみません!ちょっとした基本的なことから始めましょう。

あなたが実行しているものは、パラメータスニッフィングと呼ばれています

これは、ちょっとした奇妙な問題を解決する方法です。名前はすぐに舌から出てきます。リスのドイツ語のように。

そして、それは通常あなたの友人です。

クエリがサーバーにヒットすると、プランをコンパイルする必要があります。後で時間とリソースを節約するために、パラメータがコードを処理して返す推定行に基づいて実行計画がキャッシュされます。

これがうまくいかないことを想像する最も簡単な方法は、2つの一方的な母集団から物事を数える必要があるストアドプロシージャを想像することです。

例えば:

  • 負傷していないCrossFitシャツを着ている人:ゼロ

  • ひるんだときにひるむCrossFitシャツを着ている人:すべて

明らかに、そのコードの実行は別の実行よりも多くの作業を行う必要があり、まったく異なる量の作業を実行するクエリプランはまったく異なるように見えます。

私は何に反対ですか?

これは、見つける、テストする、修正するのが本当に難しい問題です。

  • 一貫して発生しないため、見つけるのは難しい
  • どのパラメーターが異なる計画を引き起こすかを知る必要があるため、テストするのは難しい
  • クエリとインデックスのチューニングが必要になる場合があるため、修正が難しい
  • クエリやインデックスを変更できない可能性があるため、修正が困難です
  • クエリまたはインデックスを変更しても、まだ戻ってくる可能性があるため、修正するのは困難です

クイックフィックス

時には、必要なのは少し明確にするだけです。むしろ、あなたの計画キャッシュはそうします。

ストアドプロシージャの場合

実行してみてください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スキャン、インデックスの断片化、その他の人が気を散らすものに夢中になりすぎないようにしてください。

通常、非常に基本的なインデックス作成の問題があります。コードを少し書き換える必要がある場合があります。

パラメータスニッフィングの詳細を知りたい場合:

あなたがこれを読んでいて、リンクや役に立つツールを見逃したと思うなら、コメントを残してください。これを最新の状態に保つために最善を尽くします。



28

パラメータスニッフィングは、クエリのパフォーマンスが変化する唯一の原因ではありません。次の一般的な理由のいずれかが同じ症状を示す場合があります。

  1. データ配布/ボリュームが変更され、オプティマイザーの検索ツリーの決定の転換点を通過
  2. インデックス/ファイルが断片化した
  3. 統計が更新/追加/削除されたか、データの変更により古くなり誤解を招くようになった
  4. Windowsメモリ使用率が変更されました
  5. トランザクションログがいっぱいで切り捨てられないため、物理ファイルが繰り返し展開される
  6. スキーマの変更-インデックス/インデックス付きビュー/列/制約の追加、変更、削除、データ型の変更など
  7. トレースフラグの設定が変更されました
  8. Windowsアップデートが適用されました
  9. データベースまたはサーバーの設定が変更されました
  10. サーバーCUレベルが変更されました
  11. クライアントアプリケーションのセッション設定が変更されました

このリストの項目6〜11は、何らかの明示的なアクションが実行された後にのみ発生します。あなたはそれらを除外するつもりだったと思いますが、多くの場合、チャレンジを経験している人は他の誰かが変更を加えたことに気づいていないので、プランキャッシュエントリをクリアする前にチェックする価値があります。


1
編集ポールに感謝します。@sp_BlitzErik-特定のトピックに関するアドバイスを提供するつもりはありませんでした。単にそれらが存在し、チェックする価値があるという認識を高めるためです。これは、あなたの素晴らしい投稿を減らすことを意味するものではありません。パラメーターのスニッフィングは、プロとして、そしてユーモアに基づいて深く対処しました。私はそれを読んで楽しんだ。ここで誰かがキャッチーなタイトルに続いてこの投稿にアクセスした場合にのみ、別の潜在的な原因を認識できるようにしたいだけです。私見それはあなたの投稿に価値を追加しますが、それでも私にそれを削除して欲しいなら、私に知らせてください。
SQLRaptor

いいえ、まったくありません。間違っていたり有害でない答えを削除するように誰かに頼むことはありません。まだ詳細を追加できると思いますが、最終的にはあなた次第です。
エリックダーリン

10

助けがなかった場合に備えて既存の回答に追加するために、次の日にクエリが「突然」異なる動作をするとき、以下を確認してください。

  • 使用されたテーブルのスキームは前回から変更されましたか?SSMSの場合、オブジェクトエクスプローラーでサーバーを右クリックし、を選択できますReports → Standard Reports → Schema Changes History
  • アイテム数は劇的に増加しましたか?使用したテーブルに大量のデータがある場合、クエリが非常に遅くなる可能性があります。
  • 他の誰かがあなたと同時にデータベースを利用していますか?お互いの作業に干渉しないタイムスロットを選択することもできます。
  • システム統計はどのように見えますか?サーバーがホットで実行されており、CPUをスロットリングしているか、ハードドライブのスペースまたはスワップが不足している可能性があります。サーバールームの火災や洪水など、別のハードウェアの問題がある可能性があります。

7

もう1つの可能性は、インフラストラクチャチームがVMware上のvMotionなどのツールを使用しており、SQLインスタンスをサポートするVMがDBAに気付かれずにホストからホストにシームレスに移動されることです。

これは、インフラストラクチャが外部委託されている場合の本当の問題です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.