ヒストグラム外のカーディナリティー推定


14

セットアップ

カーディナリティの推定値を理解するのに苦労しています。テストのセットアップは次のとおりです。

  • Stack Overflowデータベースの2010バージョン
  • SQL Server 2017 CU15 + GDR(KB4505225)-14.0.3192.2
  • 新しいCE(互換性レベル140)

私はこのプロシージャを持っています:

USE StackOverflow2010;
GO

CREATE OR ALTER PROCEDURE #sp_PostsByCommentCount
    @CommentCount int
AS
BEGIN
    SELECT * 
    FROM dbo.Posts p
    WHERE 
        p.CommentCount = @CommentCount
    OPTION (RECOMPILE); 
END;
GO

dbo.Postsテーブルに非クラスター化インデックスまたは統計がありません(にクラスター化インデックスがありますId)。

このための推定プランを要求すると、「推定行」dbo.Postsは1,934.99になります。

EXEC #sp_PostsByCommentCount @CommentCount = 51;

次の統計オブジェクトは、推定プランを要求したときに自動的に作成されました。

DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);

SSMSで出力される統計のスクリーンショット

そのハイライトは次のとおりです。

  • 統計のサンプルレートは1.81%と非常に低い(67,796 / 3,744,192)
  • 31のヒストグラムステップのみが使用されました
  • 「すべての密度」の値は次のとおりです0.03030303(33の異なる値がサンプリングされました)
  • RANGE_HI_KEYヒストグラムの最後は50でEQ_ROWS、1

質問

50を超える値(2,147,483,647まで)を渡すと、1,934.99行の推定値になります。 この推定値を生成するために使用される計算または値は何ですか? ちなみに、従来のカーディナリティ推定器は、1行の推定値を生成します。

私が試したこと

ここに私が持っていたいくつかの理論、私が試したもの、または私がこれを調べながら掘り出すことができた追加の情報があります。

密度ベクトル

最初は、を使用した場合と同じように、密度ベクトルになると考えましたOPTION (OPTIMIZE FOR UNKNOWN)。しかし、この統計オブジェクトの密度ベクトルは3,744,192 * 0.03030303 = 113,460なので、そうではありません。

拡張イベント

イベントを収集する拡張イベントセッションを実行してみquery_optimizer_estimate_cardinalityました(Paul Whiteのブログ投稿「カーディナリティの推定:密度統計の結合」から学びました)。

<CalculatorList>
  <FilterCalculator CalculatorName="CSelCalcColumnInInterval" Selectivity="-1.000" 
                    CalculatorFailed="true" TableName="[p]" ColumnName="CommentCount" />

  <FilterCalculator CalculatorName="CSelCalcAscendingKeyFilter" Selectivity="0.001" 
                    TableName="[p]" ColumnName="CommentCount" UseAverageFrequency="true" 
                    StatId="4" />
</CalculatorList>

したがって、CSelCalcAscendingKeyFilter電卓が使用されたように見えます(他の電卓は、それが意味するものは何でも失敗したと言います)。この列はキーではなく、一意でも、必ずしも昇順でもありません。

その用語のいくつかのグーグルを行うと、いくつかのブログ投稿につながりました:

これらのポストは、新しいCEが密度ベクトルと統計の修正カウンターの組み合わせに基づいてこれらのヒストグラム外推定値に基づいていることを示しています。残念ながら、密度ベクトルは既に除外されており(と思う?!)、修正カウンターはゼロです(sys.dm_db_stats_propertiesとにかく)。

トレースフラグ

フォレストは、TF 2363をオンにして、推定プロセスに関する詳細情報を取得することを提案しました。その出力から最も関連することはこれだと思います:

Plan for computation:

  CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)

Selectivity: 0.000516798

これは突破口です(ありがとう、フォレスト!):その0.000516798数(Selectivity="0.001"上記のXE 属性では役に立たないように丸められているようです)にテーブル内の行数を掛けたものが、私が探していた推定値です(1,934.99)。

私はおそらく明らかな何かを見逃していますが、その選択性の値がCSelCalcAscendingKeyFilter計算機内でどのように生成されるかをリバースエンジニアリングすることはできませんでした。

回答:


13

私のテストに基づいて、範囲外カーディナリティの推定値は、行カウントの平方根であり、最後の統計情報の更新以降に追加された行数で下に制限され、値ごとの平均行で上に制限されます。

あなたの場合、1,934.99 = SQRT(3744192)

以下のテスト設定:

--setup
USE TestDB
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS OFF
GO

DROP TABLE IF EXISTS dbo.Hist

CREATE TABLE dbo.Hist (
ID int identity primary key,
Num int
)

INSERT dbo.Hist
SELECT TOP 300
(ROW_NUMBER() OVER(ORDER BY(SELECT 1/0)))%3
FROM master..spt_values a
CROSS JOIN master..spt_values b
--Get estimated plan
--don't forget to run right after setup to auto-create stats
SELECT *
FROM dbo.Hist
WHERE Num = 1000
--gradually add rows, then rerun estimate above
INSERT dbo.Hist
SELECT TOP 100
-1
FROM master..spt_values a
--I sure hope you weren't testing this in prod (cleanup)
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS ON
GO

驚くべきことに、このアプローチから生成された行の推定値は、合計400行で20行、900行で30行、1600行で40行などです。

ただし、10000を超えると、行の見積もりは100で最大になります。これは、既存の統計の値ごとの行数です。10行のみを追加すると、sqrt(300)> 10であるため、推定値は10に設定されます。

したがって、推定値は次の式を使用して表現できます。

Estimate = MIN(SQRT(AC), MIN(AR, MC))

統計がサンプリングされる場合、MCは考慮されないことに注意してください。したがって、式は次のようになります。

Estimate = MIN(SQRT(AC), AR))

どこ

  • MCは「変更カウント」(統計が作成されてからの変更の数)です
  • ACは「調整されたカーディナリティー」(統計からの行数とMC)です。
  • ARは値ごとの平均行(統計の行数を列の個別の値で割った値)

これらの推定値の計算式、および計算機に関するその他の詳細については、このブログ記事「CSelCalcAscendingKeyFilter Calculatorからの推定値の分析」を参照してください。

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