web-dev-qa-db-ja.com

SQL Server 2008R2から2014sp2にアップグレードした後のクエリが遅くなる

最近、SQL Server 2008R2から2014SP2にアップグレードし、データベースを互換性レベル120にアップグレードしました。

このクエリは、古いカーディナリティエスティメータ(トレースフラグ9481が有効)でより優れた実行プランを生成します: https://www.brentozar.com/pastetheplan/?id=Hy9skV1Ox
object2で269の論理読み取りのみを使用し、object3で3を使用します。

新しいカーディナリティ推定器を使用して、この実行プランを取得します: https://www.brentozar.com/pastetheplan/?id=BJAnpXk_e
残念ながら、これにより、object2で269の論理読み取り、object3で68688の論理読み取りが発生します。

サーバーはアドホックワークロード用に構成されています。
トレースフラグ4199を有効にしても、見積もり/実行計画は改善されません

新しいカーディナリティエスティメータがなぜこのようなより悪い計画を生成するのですか
なぜこれまでの見積もりがずれているのですか?
新しいエスティメータを無効にするか、クエリヒントを使用する以外に、それを改善するにはどうすればよいですか?

2
Azrael

あなたが経験したクエリプランの回帰に失望しました。ただし、Microsoftは、カーディナリティエスティメータに関するいくつかの主要な前提を変更しました。一部のクエリプランの回帰を回避できませんでした。 Juergen Thomasを引用するには

ただし、これもかなり明確に述べると、既存のCEと比較してリグレッションを回避することが目標ではありませんでした。新しいSQL Server 2014 CEは、QFEの原則に従って統合されていません。これは、新しいSQL Server 2014 CEが多くのクエリ、特に複雑なクエリに対してより優れた計画を作成することを期待していますが、一部のクエリについては、古いCEがもたらしたよりも悪い計画をもたらすことにもなります。

最初の質問に答えるために、オプティマイザはObject2からの1行のカーディナリティの見積もりの​​ため、新しいCEでより悪い計画を選択するように見えます。これにより、ネストされたループ結合がオプティマイザにとって非常に魅力的になります。ただし、Object2から返された実際の行数は34182でした。これは、ネストされたループプランの推定コストが約30000Xだけ少なく見積もられたことを意味します。

レガシーCEは、Object2から208.733カーディナリティの見積もりを提供します。これはまだかなり遠いですが、マージ結合を使用する計画にネストされたループ結合計画よりも低い推定コストを与えることで十分です。 SQL Serverは、Object3の非クラスター化インデックスシークに0.0032831のコストを与えました。レガシーCEでのネストされたループプランでは、208インデックスシークの合計コストは約0.0032831 * 208.733 = 0.68529になると予想できます。これは、マージ結合プランの最終的な推定サブツリーコスト0.0171922よりもはるかに高くなります。

2番目の質問に答えるために、カーディナリティは、クエリがMicrosoftによって実際に公開されているのと同じくらい簡単なクエリの式を推定します。発見されたレガシーCEと新しいCEの違いについての優れたホワイトペーパーを参照することをお勧めします here 。カーディナリティの推定値が新しいCEで1、レガシーCEで208.733である理由に注目してください。レガシーCEはフィルターの独立性を前提としていますが、新しいCEは指数バックオフを使用するため、これは予想外です。一般に、このようなクエリでは、新しいCEがObject2のカーディナリティの推定値を大きくすると予想します。 Object2の統計を見て、何が起こっているのかを理解できるはずです。

3番目の質問に答えるために、ホワイトペーパーから一般的な戦略を得ることができます。以下は省略された引用です:

  • 特定のクエリが依然としてメリットがある場合は、新しいCE設定を保持し、別の方法を使用してパフォーマンスの問題を「回避する」ようにします。
  • 新しいCEを保持し、新しいCEによって直接パフォーマンスが低下したクエリには、トレースフラグ9481を使用します。
  • 古いデータベース互換性レベルに戻し、新しいCEを使用してパフォーマンスが向上したクエリには、トレースフラグ2312を使用します。
  • 基本的な基数推定スキューのトラブルシューティング方法を使用します。
  • レガシーCEに完全に戻します。

特にあなたの問題については、最初に統計に焦点を当てます。 Object3でのインデックススキャンのカーディナリティの見積もりがこれほど遠いのはなぜかはわかりません。さらにテストを行う前に、関連するすべてのオブジェクトとインデックスのFULLSCANで統計を更新することをお勧めします。 CEの変更後に統計を再度更新することも、良いステップです。ホワイトペーパーを使用して、表示されているカーディナリティの見積もりが表示される理由を正確に理解できるはずです。

詳しい情報をご提供いただければ、さらに詳しいサポートを提供させていただきます。あなたのIPを保護したいのですが、非常に単純なクエリがあります。テーブルと列の名前を変更して、正確なクエリテキスト、関連するテーブルDDL、インデックスDDL、および統計に関する情報を提供できますか?

他のすべてが失敗し、ヒントやトレースフラグなしで修正する必要がある場合は、SQL Server 2016に更新するか、テーブルのインデックスを変更してみてください。インデックスを削除しても、ネストされたループプランが正しくない可能性は低いですが、インデックスを削除すると、他のクエリに悪影響が及ぶ可能性があります。

3
Joe Obbish

何らかの理由で、新しいCEは異なるインデックスを使用しています。どちらのインデックスも1行の推定を提供するため、不適切なループ結合になります。
あなたは両方のテーブルの統計をWITH FULLSCANで更新する立場にありますか?それでも問題が解決しない場合は、テーブルとインデックスの定義を投稿してください(匿名のテーブル/列/インデックス名のみを使用)。

サイド:

サンプルコードのObjectXエイリアシングは非常に混乱します。特に、より複雑なクエリの場合は、次回匿名化する必要があるときに再検討した方がよいでしょう。 XがObjectXと一致するすべてのエイリアスのAliasXは、改善になる可能性があります。

ちなみに、nolockの一貫した使用を注意深く検討していない場合は、次の記事を読むことをお勧めします。 https://sqlperformance.com/2015/04/t-sql-queries/the-read-非コミット分離レベル

0
T.H.