Estimation de la cardinalité en dehors de l'histogramme


14

Installer

J'ai du mal à comprendre une estimation de cardinalité. Voici ma configuration de test:

  • la version 2010 de la base de données Stack Overflow
  • SQL Server 2017 CU15 + GDR (KB4505225) - 14.0.3192.2
  • le nouveau CE (niveau de compatibilité 140)

J'ai ce 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

Il n'y a pas d'index ou de statistiques non cluster sur la dbo.Poststable (un index cluster est activé Id).

Lorsque vous demandez un plan estimé pour cela, les "lignes estimées" qui en sortent dbo.Postssont de 1 934,99:

EXEC #sp_PostsByCommentCount @CommentCount = 51;

L'objet de statistiques suivant a été créé automatiquement lorsque j'ai demandé le plan estimé:

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

capture d'écran de la sortie des statistiques dans SSMS

Les faits saillants sont les suivants:

  • Les statistiques ont un taux d'échantillonnage assez faible de 1,81% (67 796/3 744 192)
  • Seulement 31 étapes d'histogramme ont été utilisées
  • La valeur «Toute densité» est 0.03030303(33 valeurs distinctes ont été échantillonnées)
  • Le dernier RANGE_HI_KEYde l'histogramme est 50, avec EQ_ROWS1

Question

Le dépassement de toute valeur supérieure à 50 (jusqu'à 2 147 483 647 inclus) entraîne l'estimation de la ligne 1 934,99. Quel calcul ou valeur est utilisé pour produire cette estimation? L'estimateur de cardinalité hérité produit une estimation d'une ligne, soit dit en passant.

Ce que j'ai essayé

Voici quelques théories que j'ai eues, des choses que j'ai essayées ou des informations supplémentaires que j'ai pu creuser en y réfléchissant.

Vecteur de densité

J'ai d'abord pensé que ce serait le vecteur de densité, le même que si j'avais utilisé OPTION (OPTIMIZE FOR UNKNOWN). Mais le vecteur de densité pour cet objet stats est 3,744,192 * 0,03030303 = 113,460, donc ce n'est pas ça.

Événements prolongés

J'ai essayé de lancer une session Extended Event qui a collecté l' query_optimizer_estimate_cardinalityévénement (dont j'ai entendu parler dans le billet de blog de Paul White, Cardinality Estimation: Combining Density Statistics ), et j'ai obtenu ce genre d'informations intéressantes:

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

Il semble donc que la CSelCalcAscendingKeyFiltercalculatrice ait été utilisée (l'autre dit qu'elle a échoué, quoi que cela signifie). Cette colonne n'est pas une clé, ni unique, ni nécessairement ascendante, mais peu importe.

Faire une recherche sur Google de ce terme m'a conduit à quelques articles de blog:

Ces messages indiquent que le nouveau CE fonde ces estimations hors de l'histogramme sur une combinaison du vecteur de densité et du compteur de modification de la statistique. Malheureusement, j'ai déjà exclu le vecteur de densité (je pense?!), Et le compteur de modifications est nul (de sys.dm_db_stats_propertiestoute façon).

Trace Flags

Forrest m'a suggéré d'activer TF 2363 pour obtenir plus d'informations sur le processus d'estimation. Je pense que la chose la plus pertinente de cette sortie est la suivante:

Plan for computation:

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

Selectivity: 0.000516798

C'est une percée (merci, Forrest!): Ce 0.000516798nombre (qui semble avoir été arrondi de manière inutile dans l' Selectivity="0.001"attribut XE ci-dessus) multiplié par le nombre de lignes dans le tableau est l'estimation que je cherchais (1934,99).

Il me manque probablement quelque chose d'évident, mais je n'ai pas réussi à inverser la façon dont cette valeur de sélectivité est produite à l'intérieur de la CSelCalcAscendingKeyFiltercalculatrice.

Réponses:


13

Sur la base de mes tests, l'estimation de la cardinalité hors limites est simplement la racine carrée du nombre de lignes, limitée en dessous par le nombre de lignes ajoutées depuis la dernière mise à jour des statistiques, et limitée au-dessus par la moyenne des lignes par valeur.

Dans votre cas, 1934,99 = SQRT (3744192)

Configuration de test ci-dessous:

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

Étonnamment, même des estimations de lignes ont été générées à partir de cette approche: 20 à 400 lignes au total, 30 à 900, 40 à 1600, etc.

Au-delà de 10000 cependant, l'estimation des lignes atteint un maximum de 100, ce qui correspond au nombre de lignes par valeur dans les statistiques existantes. L'ajout de seulement 10 lignes définira l'estimation à 10, car sqrt (300)> 10.

Ainsi, les estimations pourraient être exprimées en utilisant cette formule:

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

Notez que si des statistiques sont échantillonnées, alors MC n'est pas pris en compte. La formule devient donc:

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

  • MC est le "nombre de modifications" (nombre de modifications depuis la création des statistiques)
  • AC est la "cardinalité ajustée" (nombre de lignes des statistiques plus MC),
  • AR est la moyenne des lignes par valeur (nombre de lignes des statistiques divisé par des valeurs distinctes dans la colonne)

Les formules de ces estimations et d'autres détails sur la calculatrice se trouvent dans cet article de blog: Analyse des estimations à partir de la calculatrice CSelCalcAscendingKeyFilter

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.