SQL Serverは、述語が相関していることをどのように知っていますか?


15

:診断しながら、SQL Server 2008 R2のが悪いカーディナリティ推定(シンプルインデックスにもかかわらず、最新の統計情報など)ので、貧弱なクエリ計画を照会し、私はおそらく関連のKBの記事見つけ クエリを実行するとパフォーマンスの低下:FIXをSQL Server 2008またはSQL Server 2008 R2またはSQL Server 2012の相関AND述語を含む

KB記事の意味は「相関」によって推測できます。たとえば、述語#2と述語#1は、主に同じ行を対象としています。

しかし、SQL Serverがこれらの相関関係をどのように認識しているかはわかりません。テーブルには、両方の述語の列を含む複数列のインデックスが必要ですか?SQLは統計を使用して、ある列の値が別の列と相関しているかどうかを確認しますか?または、他の方法が使用されていますか?

私はこれを2つの理由で尋ねています:

  1. この修正プログラムを使用してどのテーブルとクエリが改善される可能性があるかを判断するには
  2. #1に影響を与えるためにインデックス作成、統計などで何をすべきかを知るため

回答:


20

次に示す簡単なAdventureWorksクエリと実行計画を検討してください。クエリにはに接続された述語が含まれていANDます。オプティマイザーのカーディナリティの推定値は41,211行です。

-- Estimate 41,211 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336
    AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';

デフォルトの実行計画

デフォルト統計の使用

単一列の統計のみを指定すると、オプティマイザは各述語のカーディナリティを個別に推定し、結果の選択度を乗算することによりこの推定値を生成します。このヒューリスティックは、述語が完全に独立していることを前提としています。

クエリを2つの部分に分割すると、計算が見やすくなります。

-- Estimate 68,336.4 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336;

Transaction Historyテーブルには合計113,443行が含まれているため、68,336.4の見積もりは、この述部の選択性68336.4 / 113443 = 0.60238533表します。この推定値は、TransactionID列のヒストグラム情報とクエリで指定された定数値を使用して取得されます。

-- Estimate 68,413 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';

この述部の推定選択性は、68413.0 / 113443 = 0.60306056です。この場合も、述部の定数値とTransactionDate統計オブジェクトのヒストグラムから計算されます。

述部が完全に独立していると仮定すると、2つの述部を乗算することにより、2つの述部の選択性を推定できます。最終的なカーディナリティの推定値は、結果の選択度にベーステーブルの113,443行を乗算することによって取得されます。

0.60238533 * 0.60306056 * 113443 = 41210.987

丸め後、これは元のクエリで見られた41,211の推定値です(オプティマイザーは内部で浮動小数点演算も使用します)。

素晴らしい見積もりではありません

TransactionIDそしてTransactionDate列は、(単調頻繁に行うキーと日付列を増やすなど)のAdventureWorksデータセット内の密接な関係を持っています。この相関は、独立性の仮定に違反していることを意味します。結果として、実行後のクエリプランには、推定41,211行ではなく68,095行が表示されます。

実行後計画

トレースフラグ4137

このトレースフラグを有効にすると、述語の結合に使用されるヒューリスティックが変更されます。完全に独立していると仮定する代わりに、オプティマイザーは、2つの述部の選択性が十分に近く、相関している可能性が高いと見なします。

-- Estimate 68,336.4
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336
    AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13'
OPTION (QUERYTRACEON 4137);

TransactionID述部だけで68,336.4行が推定され、述部だけで68,413行が推定されたことを思い出してくださいTransactionDate。オプティマイザーは、選択性を乗算するのではなく、これら2つの推定値のうち低い方を選択しました。

もちろん、これは単なるヒューリスティックですが、相関するAND述語を使用したクエリの推定値を改善するのに役立つ可能性があります。各述語は考えられる相関について考慮され、多くのAND句が関係する場合は他の調整が行われますが、その例はその基本を示すのに役立ちます。

複数列の統計

これらは相関のあるクエリで役立ちますが、ヒストグラム情報は依然として統計の先頭の列のみに基づいています。したがって、以下の複数列統計の候補は重要な点で異なります。

CREATE STATISTICS
    [stats Production.TransactionHistory TransactionID TransactionDate]
ON Production.TransactionHistory
    (TransactionID, TransactionDate);

CREATE STATISTICS
    [stats Production.TransactionHistory TransactionDate TransactionID]
ON Production.TransactionHistory
    (TransactionDate, TransactionID);

それらのうちの1つだけを見ると、唯一の追加情報は「すべて」の密度の追加レベルであることがわかります。ヒストグラムには、TransactionDate列に関する詳細情報のみが含まれています。

DBCC SHOW_STATISTICS
    (
        'Production.TransactionHistory', 
        'stats Production.TransactionHistory TransactionDate TransactionID'
    );

複数列の統計

これらの複数列の統計を適切に配置すると...

SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336
    AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';

...実行計画には、単一列の統計のみが利用可能な場合とまったく同じ推定値が表示されます。

複数列の統計計画

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