部分的にカバーする範囲の述語の優先度推定


13

現時点では、ヒストグラムステップを部分的にカバーする範囲述部のカーディナリティをSQL Serverがどのように評価するかを理解しようとしています。

インターネット上で、ステップ内統計値の基数推定で、私は同様の質問に出くわし、Paul Whiteはそれに対してかなり興味深い答えを出しました。

Paulの答えによれば、述語> =および>のカーディナリティーを推定するための式(この場合、少なくとも120のカーディナリティー推定モデルにのみ興味があります)は次のとおりです。

>の場合:

Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1)))

> =の場合:

Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))

TransactionDate列と '20140614'から '20140618'までの日時の範囲を使用して、範囲の述語に基づいてAdventureWorks2014データベースの[Production]。[TransactionHistory]テーブルでこれらの式の適用をテストしました。

この範囲のヒストグラムステップの統計は次のとおりです。

ヒストグラム

式に従って、次のクエリの基数を計算しました。

SELECT COUNT(1)
FROM [AdventureWorks2014].[Production].[TransactionHistory]
WHERE [TransactionDate] BETWEEN '20140615 00:00:00.000' AND '20140616 00:00:00.000'

計算は、次のコードを使用して実行されました。

  DECLARE @predStart DATETIME =  '20140615 00:00:00.000'
  DECLARE @predEnd DATETIME = '20140616 00:00:00.000'

  DECLARE @stepStart DATETIME = '20140614 00:00:00.000'
  DECLARE @stepEnd DATETIME = '20140618 00:00:00.000'

  DECLARE @predRange FLOAT = DATEDIFF(ms, @predStart, @predEnd)
  DECLARE @stepRange FLOAT = DATEDIFF(ms, @stepStart, @stepEnd)

  DECLARE @F FLOAT = @predRange / @stepRange;

  DECLARE @avg_range_rows FLOAT = 100.3333
  DECLARE @distinct_range_rows INT = 3
  DECLARE @EQ_ROWS INT = 0

  SELECT @F AS 'F'

  --for new cardinality estimator

  SELECT @EQ_ROWS + @avg_range_rows * (@F * (@distinct_range_rows - 1) + 1) AS [new_card]

計算後、次の結果が得られました。

ここに画像の説明を入力してください

式によれば、150.5でしたが、オプティマイザーは225.75行で述語を推定します。述語の上部境界線を「20140617」に変更すると、オプティマイザーは既に250.833行を評価しますが、 200.6666行。

この場合、Cardinality Estimatorはどのように評価されますか?


SQL Serverの2014 12.0.5 SP2
ПавелКовалёв

回答:


12

SQL Serverは、さまざまな状況でさまざまな計算を使用します。あなたの例はリンクされたQ&Aとは異なります。なぜならあなたの範囲は完全にステップに含まれているからです。ステップの境界を越えることはありません。また、1つではなく2つの端を持つ間隔です。書き込みは、BETWEEN2つの別々の述語を書くことと同じである>=<=

単一ステップ内の2つの境界のある間隔

数式は、予想される異なる値の数に対してステップ内で線形補間を実行するように変更され、1つではなく2つの範囲のエンドポイントが指定された(そしてヒストグラムステップ内に存在すると想定される)ことを反映します。

質問で与えられたヒストグラムのステップを使用して:

質問ヒストグラムステップ

のクエリのBETWEEN '20140615' AND '20140616'場合、計算は次のとおりです。

DECLARE
    @Q1 float = CONVERT(float, CONVERT(datetime, '2014-06-15')),
    @Q2 float = CONVERT(float, CONVERT(datetime, '2014-06-16')),
    @K1 float = CONVERT(float, CONVERT(datetime, '2014-06-14')),
    @K2 float = CONVERT(float, CONVERT(datetime, '2014-06-18')),
    @RANGE_ROWS float = 301,
    @DISTINCT_RANGE_ROWS float = 3;

DECLARE
    @S1 float = (@Q1 - @K1) / (@K2 - @K1),
    @S2 float = (@Q2 - @K1) / (@K2 - @K1);

DECLARE
    @F float = @S2 - @S1;

DECLARE
    @AVG_RANGE_ROWS float = @RANGE_ROWS / @DISTINCT_RANGE_ROWS;

SELECT
    @AVG_RANGE_ROWS * ((@F * (@DISTINCT_RANGE_ROWS - 2)) + 2);

... 225.75を与えます@Q2から'20140616'に変更すると'20140617'、結果は250.833になりますます。

両方の結果は、質問で与えられた結果と一致します。

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