web-dev-qa-db-ja.com

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

[あいさつ]

(1つチェック)

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

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

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

それはうまくいっていました(該当する場合)

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

今は急に遅くなっています。

ブロックされていないこと、および長時間実行されているメンテナンスタスク、レポート、またはその他の帯域外プロセスの被害を受けていないことを確認しました。

何が問題なのか、何をすべきか、そして何らかの助けを得るためにどのような情報を提供できますか?

[*Insert appropriate closing remarks*]
77
Erik Darling

[ここにあなたの名前]様!

ああ、ごめんなさい! Jiffyで修正するための基本から始めましょう。

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

これは、奇抜で奇妙な問題を解決する方法です。その名は舌から転がり落ちる。リスのドイツ語のように。

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

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

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

例えば:

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

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

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

私は何に反対していますか?

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

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

クイックフィックス

場合によっては、必要なのは少し明快です。むしろ、あなたの計画キャッシュはそうします。

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

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;

NUTS

クエリが現在実行されていない場合は、 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';

これらのいずれからもかなり類似した出力が表示されるはずです。繰り返しになりますが、クールで青いクリック感のある列を招くクエリプランは、あなたの友達です。

NUTS

プランを共有する最も簡単な方法は、 Paste The Plan *を使用するか、XMLをPastebinにダンプすることです。それを取得するには、青いクリックしやすい列が表示されているいずれかをクリックします。クエリプランが新しいSSMSタブに表示されます。

NUTS

会社のコードとクエリを共有することに不満がある場合は、 Sentry Oneの無料のプランエクスプローラーツール を使用してプランを匿名化できます。覚えておいてください、これは助けを得ることを難しくします-匿名化されたコードは読んで理解するのがはるかに難しくなります。

話し合ったこれらのツールはすべて、クエリテキストを返すはずです。ここでは他に何もする必要はありません。

パラメータの取得はもう少し難しいです。 プランエクスプローラー を使用している場合は、下部にタブがあり、すべてが一覧表示されます。

NUTS

sp_BlitzCache *を使用している場合は、ストアドプロシージャの実行ステートメントを提供するクリック可能な列があります。

NUTS

テーブルとインデックスの定義を取得する

SSMSで簡単に右クリックして、スクリプトを作成できます。

NUTS

すべてを一度に取得したい場合は、テーブルを直接指すと、 sp_BlitzIndex *が役立ちます。

EXEC dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow2010',
                       @SchemaName = 'dbo',
                       @TableName = 'Users';

これにより、テーブル定義(createステートメントとしてではありません)、およびすべてのインデックスのcreateステートメントが提供されます。

この情報を収集して質問に追加すると、人々に役立つ十分な情報が提供されるか、正しい方向に向けられるはずです。

自分でやりたい!

まあ、かっこいい。嬉しいです。あなたは狂った人です。

パラメータスニッフィングを「修正」すると人々が考える方法はたくさんあります。

しかし、これらは実際には、さまざまな方法でパラメータースニッフィングを無効にするだけです。彼らが問題を解決できないと言っているのではなく、根本的な原因を突き止めていないだけです。

根本的な原因に到達することは、通常、一種の難しいからです。あなたはそれらの厄介な「計画の品質の問題」を探す必要があります。

高速プランと低速プランから始めて、次のような違いを探します。

  • 使用されるインデックス
  • 注文に参加
  • シリアルvsパラレル

また、コードをパラメータスニッフィングに敏感にするさまざまな演算子を探します。

  • ルックアップ
  • 並べ替え
  • 結合タイプ
  • メモリーの付与(および拡張により、流出)
  • スプール

シークVSスキャン、インデックスの断片化、または人々が裾を回って見回す貨物のカルティカルなものに巻き込まれないでください。

通常、かなり基本的な索引付けの問題があります。時々、コードは少し書き直す必要があります。

パラメータスニッフィングについて詳しく知りたい場合:

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


89
Erik Darling

クエリのパフォーマンスが変動する原因として考えられるのは、パラメータスニッフィングだけではありません。次の一般的な理由のいずれかが同じ症状を示す可能性があります。

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

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

27
SQLRaptor

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

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

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

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

7
pacreely