Kardinalitätsschätzung außerhalb des Histogramms

14

Installieren

Ich habe Probleme beim Verstehen einer Kardinalitätsschätzung. Hier ist mein Testaufbau:

  • die 2010-Version der Stack Overflow-Datenbank
  • SQL Server 2017 CU15 + DDR (KB4505225) - 14.0.3192.2
  • das neue CE (Kompatibilitätsstufe 140)

Ich habe diesen proc:

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

Die dbo.PostsTabelle enthält keine nicht gruppierten Indizes oder Statistiken (ein gruppierter Index ist vorhanden Id).

Wenn Sie nach einem geschätzten Plan für diesen dbo.PostsVorgang fragen, werden als "geschätzte Zeilen" 1.934,99 ausgegeben:

EXEC #sp_PostsByCommentCount @CommentCount = 51;

Das folgende Statistikobjekt wurde automatisch erstellt, als ich nach dem geschätzten Plan gefragt habe:

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

Screenshot der Statistikausgabe in SSMS

Die Highlights davon sind:

  • Die Statistiken haben eine recht niedrige Abtastrate von 1,81% (67.796 / 3.744.192).
  • Es wurden nur 31 Histogrammschritte verwendet
  • Der Wert "Alle Dichte" ist 0.03030303(33 verschiedene Werte wurden abgetastet).
  • Das letzte RANGE_HI_KEYim Histogramm ist 50 mit EQ_ROWS1

Frage

Wenn Sie einen Wert über 50 (bis einschließlich 2.147.483.647) übergeben, wird die Zeilenschätzung auf 1.934,99 festgelegt. Welche Berechnung oder welcher Wert wird verwendet, um diese Schätzung zu erstellen? Der Legacy-Kardinalitätsschätzer erzeugt übrigens eine Schätzung von 1 Zeile.

Was ich versucht habe

Hier sind einige Theorien, die ich hatte, Dinge, die ich ausprobiert habe, oder zusätzliche Informationen, die ich ausgraben konnte, als ich mich damit befasste.

Dichtevektor

Ich dachte anfangs, es wäre der Dichtevektor, so als hätte ich ihn benutzt OPTION (OPTIMIZE FOR UNKNOWN). Der Dichtevektor für dieses Statistikobjekt ist jedoch 3.744.192 * 0.03030303 = 113.460, das ist es also nicht.

Erweiterte Veranstaltungen

Ich habe versucht, eine erweiterte Ereignissitzung durchzuführen, in der das query_optimizer_estimate_cardinalityEreignis gesammelt wurde (was ich in Paul Whites Blogbeitrag Cardinality Estimation: Combining Density Statistics erfahren habe ), und diese interessanten Leckerbissen erhalten:

<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>

Es sieht so aus, als wäre der CSelCalcAscendingKeyFilterTaschenrechner benutzt worden (der andere sagt, er sei fehlgeschlagen, was auch immer das bedeutet). Diese Spalte ist kein Schlüssel oder eindeutig oder unbedingt aufsteigend, aber was auch immer.

Das Googeln dieses Begriffs hat mich zu einigen Blog-Posts geführt:

Diese Beiträge geben die neuen CE-Grundlagen für diese Schätzungen außerhalb des Histogramms an, die auf einer Kombination des Dichtevektors und des Änderungszählers der Statistik basieren. Leider habe ich den Dichtevektor bereits ausgeschlossen (glaube ich ?!) und der Änderungszähler ist Null (pro sys.dm_db_stats_properties).

Fahnen verfolgen

Forrest schlug vor, TF 2363 einzuschalten, um weitere Informationen über den Schätzvorgang zu erhalten. Ich denke, das Relevanteste an dieser Ausgabe ist Folgendes:

Plan for computation:

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

Selectivity: 0.000516798

Dies ist ein Durchbruch (danke, Forrest!): Diese 0.000516798Zahl (die im Selectivity="0.001"obigen XE- Attribut unvollständig gerundet zu sein scheint ) multipliziert mit der Anzahl der Zeilen in der Tabelle ist die Schätzung, nach der ich gesucht habe (1.934,99).

Vermutlich fehlt mir etwas Offensichtliches, aber ich konnte nicht rückentwickeln, wie dieser Selektivitätswert im CSelCalcAscendingKeyFilterTaschenrechner erzeugt wird.

Josh Darnell
quelle

Antworten:

13

Basierend auf meinen Tests ist die Schätzung der Kardinalität außerhalb der Grenzen einfach die Quadratwurzel der Zeilenzahl, die unten durch die Anzahl der seit der letzten Statistikaktualisierung hinzugefügten Zeilen und oben durch die durchschnittlichen Zeilen pro Wert begrenzt wird.

In Ihrem Fall 1,934.99 = SQRT (3744192)

Testaufbau unten:

--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

Überraschenderweise wurden mit diesem Ansatz sogar Zeilenschätzungen generiert: 20 bei 400 Gesamtzeilen, 30 bei 900, 40 bei 1600 usw.

Nach 10000 ist die Zeilenschätzung jedoch auf 100 begrenzt, was der Anzahl der Zeilen pro Wert in den vorhandenen Statistiken entspricht. Durch Hinzufügen von nur 10 Zeilen wird die Schätzung auf 10 festgelegt, da sqrt (300)> 10.

Somit könnten die Schätzungen unter Verwendung dieser Formel ausgedrückt werden:

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

Beachten Sie, dass beim Abtasten von Statistiken MC nicht berücksichtigt wird. Die Formel lautet also:

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

Wo

  • MC ist der "Änderungszähler" (Anzahl der Änderungen seit Erstellung der Statistik)
  • AC ist die "angepasste Kardinalität" (Anzahl der Zeilen aus der Statistik plus MC),
  • AR ist der Durchschnitt der Zeilen pro Wert (Anzahl der Zeilen aus der Statistik geteilt durch unterschiedliche Werte in der Spalte)

Die Formeln für diese Schätzungen und andere Details zum Taschenrechner finden Sie in diesem Blog-Beitrag: Analysieren von Schätzungen mit dem CSelCalcAscendingKeyFilter-Taschenrechner

Wald
quelle