it-swarm.com.de

Kardinalitätsschätzung außerhalb des Histogramms

Installieren

Ich habe Probleme, eine Kardinalitätsschätzung zu verstehen. 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 Prozess:

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

Es gibt keine nicht gruppierten Indizes oder Statistiken für die Tabelle dbo.Posts (Es gibt einen gruppierten Index für Id).

Wenn Sie nach einem geschätzten Plan dafür fragen, sind die "geschätzten Zeilen", die aus dbo.Posts Herauskommen, 1.934,99:

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 of statistics output in SSMS

Die Highlights davon sind:

  • Die Statistik hat eine ziemlich 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_KEY Im Histogramm ist 50, mit EQ_ROWS Von 1

Frage

Wenn Sie einen Wert über 50 (bis einschließlich 2.147.483.647) übergeben, erhalten Sie eine Zeilenschätzung von 1.934,99. Mit welcher Berechnung oder welchem ​​Wert wird diese Schätzung erstellt? Der Legacy-Kardinalitätsschätzer erstellt ü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, während ich mich damit befasste.

Dichtevektor

Ich dachte anfangs, es wäre der Dichtevektor, genauso wie wenn ich OPTION (OPTIMIZE FOR UNKNOWN) verwendet hätte. Aber der Dichtevektor für dieses Statistikobjekt ist 3.744.192 * 0.03030303 = 113.460, das ist es also nicht.

Erweiterte Ereignisse

Ich habe versucht, eine erweiterte Ereignissitzung durchzuführen, in der das Ereignis query_optimizer_estimate_cardinality Gesammelt wurde (was ich aus Paul Whites Blogbeitrag erfahren habe Kardinalitätsschätzung: Kombinieren von Dichtestatistiken ) und habe diese Art von interessantem Ereignis erhalten Leckerbissen:

<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 scheint also, dass der Taschenrechner CSelCalcAscendingKeyFilter verwendet wurde (der andere sagt, dass er fehlgeschlagen ist, was auch immer das bedeutet). Diese Spalte ist kein Schlüssel oder eindeutig oder notwendigerweise aufsteigend, aber was auch immer.

Das Googeln dieses Begriffs führte mich zu einigen Blog-Posts:

Diese Beiträge geben an, dass das neue CE diese Schätzungen außerhalb des Histogramms auf einer Kombination des Dichtevektors und des Modifikationszählers des Stat basiert. Leider habe ich den Dichtevektor bereits ausgeschlossen (glaube ich?!) Und der Modifikationszähler ist Null (pro sys.dm_db_stats_properties Jedenfalls).

Flags verfolgen

Forrest schlug vor, TF 2363 einzuschalten, um weitere Informationen zum Schätzprozess 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.000516798 - Zahl (die im obigen XE-Attribut Selectivity="0.001" Nicht hilfreich gerundet worden zu sein scheint) multipliziert mit der Anzahl der Zeilen in der Tabelle ist die Schätzung, nach der ich gesucht habe (1.934,99).

Ich vermisse wahrscheinlich etwas Offensichtliches, aber ich konnte nicht rückentwickeln, wie dieser Selektivitätswert im CSelCalcAscendingKeyFilter -Rechner erzeugt wird.

14
Josh Darnell

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

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 aus diesem Ansatz sogar Zeilenschätzungen generiert: 20 bei 400 Gesamtzeilen, 30 bei 900, 40 bei 1600 usw.

Nach 10000 beträgt die maximale Zeilenschätzung jedoch 100, was der Anzahl der Zeilen pro Wert in den vorhandenen Statistiken entspricht. Wenn Sie nur 10 Zeilen hinzufügen, wird die Schätzung auf 10 gesetzt, da sqrt (300)> 10 ist.

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

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

Beachten Sie, dass MC nicht berücksichtigt wird, wenn Statistiken erfasst werden. So lautet die Formel:

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

Wo

  • MC ist die "Änderungszahl" (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 weitere Details zum Taschenrechner finden Sie in diesem Blogbeitrag: Analysieren von Schätzungen aus dem CSelCalcAscendingKeyFilter-Taschenrechner

13
Forrest