次の方法で共有


新しいカーディナリティ推定器での結合包含の前提条件により、クエリのパフォーマンスが低下する

この記事は、新しいカーディナリティ推定器を使用してクエリをコンパイルするときに、SQL Server 2014 以降のバージョンで発生する可能性があるパフォーマンスの問題を解決するのに役立ちます。

元の製品バージョン: SQL Server
元の KB 番号: 3189675

現象

次のような状況で問題が発生します。

  • SQL Server 2014 以降のバージョンを使用しています。
  • 結合と非結合フィルター述語を含むクエリを実行します。
  • 新しいカーディナリティ推定 (SQL Server) (新しい CE) を使用してクエリをコンパイルします。

このシナリオでは、クエリのパフォーマンス低下が発生します。

レガシ CE を使用してクエリをコンパイルした場合、この問題は発生しません。

原因

2014 年SQL Serverから、データベース互換性レベル 120 以降の新しいカーディナリティ推定 (新しい CE) が導入されました。 新しい CE は、クエリ オプティマイザーが異なる演算子と述語のカーディナリティを推定するときに使用されるモデルのレガシ CE からいくつかの前提条件を変更します。

これらの変更の 1 つは、結合包含の前提条件に関連しています。

レガシ CE モデルでは、ユーザーが常に存在するデータに対してクエリを実行することを前提としています。 つまり、2 つのテーブルの等結合操作を伴う結合述語の場合、結合された列は結合の両側に存在します。 結合テーブルに対して追加の非結合フィルター述語が存在する場合、レガシ CE では、結合述語と非結合フィルター述語に対してある程度の相関関係が想定されます。 この暗黙的な相関関係は、Simple Containment と呼ばれます。

または、新しい CE では、関連付けとして Base Containment が使用されます。 新しい CE モデルでは、ユーザーが存在しないデータを照会する可能性があることを前提としています。 つまり、個別のテーブルのフィルター述語は相互に関連付けられない可能性があります。 したがって、確率的アプローチを使用します。

多くの実用的なシナリオでは、基本包含の前提条件を使用すると、より良い見積もりが作成されます。 これにより、より効率的なクエリ プランの選択肢が作成されます。 ただし、状況によっては、Simple Containment の仮定を使用すると、より良い結果が得られます。 この場合、レガシ CE の代わりに新しい CE を使用すると、クエリ プランの選択効率が低下する可能性があります。

新しい CE に関連する問題のトラブルシューティング方法の詳細については、「SQL Server 2012 以前から 2014 以降へのアップグレード後のクエリ パフォーマンスの低下」を参照してください。

解決方法

SQL Server 2014 以降のバージョンでは、トレース フラグ 9476 を使用して、既定の基本包含の前提条件ではなく、単純な包含の前提条件を使用するようにSQL Serverを強制できます。 アプリケーション クエリを変更できる場合は、2016 (13.x) SP1 SQL Server後にクエリ ヒントASSUME_JOIN_PREDICATE_DEPENDS_ON_FILTERSを使用することをお勧めします。 詳細については、「 USE HINT」を参照してください。 例:

SELECT * FROM Table1 t1
JOIN Table2 t2
ON t1.Col1 = t2.Col1
WHERE Col1 = 10
OPTION (USE HINT ('ASSUME_JOIN_PREDICATE_DEPENDS_ON_FILTERS'));

次の条件に該当する場合、このトレース フラグを有効にするか、クエリ ヒントを使用すると、レガシ CE モデルに完全に戻すことなく、クエリ プランの選択が向上する可能性があります。

  • 最適ではないクエリ プランの選択が発生し、結合と非結合フィルター述語を含むクエリの全体的なパフォーマンスが低下します。
  • "結合カーディナリティ" 推定で有意な不正確さを確認できます (つまり、実際の行数と推定される行数が大きく異なります)。
  • レガシ CE を使用してクエリをコンパイルする場合、この不正確さは存在しません。

このトレース フラグは、グローバル、セッション レベル、またはクエリ レベルで有効にすることができます。

注:

トレース フラグを誤って使用すると、ワークロードのパフォーマンスが低下する可能性があります。 詳細については、「 ヒント (Transact-SQL) - クエリ」を参照してください。