Estimation de la cardinalité des prédicats de l'aire de répartition couvrant partiellement


13

En ce moment, j'essaie de comprendre comment SQL Server évalue la cardinalité des prédicats de plage qui couvrent partiellement l'étape d'histogramme.

Sur Internet, à cardinality-estimation-for-and-intra-step-statistics-value, je suis tombé sur une question similaire et Paul White a donné une réponse plutôt intéressante.

Selon la réponse de Paul, les formules d'estimation de la cardinalité pour les prédicats> = et> (dans ce cas, je ne suis intéressé que par le modèle d'estimation de la cardinalité d'au moins 120) sont les suivantes:

Pour>:

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

Pour> =:

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

J'ai testé l'application de ces formules sur la table [Production]. [TransactionHistory] de la base de données AdventureWorks2014 basée sur le prédicat de plage à l'aide de la colonne TransactionDate et de la plage de datetime entre '20140614' et '20140618'.

Les statistiques de l'étape d'histogramme de cette plage sont les suivantes:

Histogramme

Selon la formule, j'ai calculé la cardinalité pour la requête suivante:

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

Le calcul a été effectué à l'aide du code suivant:

  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]

Après le calcul, j'ai obtenu les résultats suivants:

entrez la description de l'image ici

Selon la formule, il s'est avéré 150,5, mais l'optimiseur estime le prédicat à 225,75 lignes, et si vous changez la bordure supérieure du prédicat en '20140617', l'optimiseur évaluera déjà 250,833 lignes, tout en utilisant la formule que nous obtenons uniquement 200,6666 lignes.

Veuillez me dire, comment Cardinality Estimator évalue-t-il dans ce cas, peut-être que j'ai fait une erreur quelque part dans ma compréhension des formules citées?


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

Réponses:


12

SQL Server utilise différents calculs dans différentes situations. Votre exemple est différent des questions et réponses liées car votre plage est entièrement contenue dans une étape; il ne franchit pas de limite de marche. C'est aussi un intervalle avec deux extrémités plutôt qu'une. L'écriture BETWEENest identique à l'écriture de deux prédicats distincts avec >=et <=.

Intervalle avec deux limites, en une seule étape

La formule est modifiée pour effectuer une interpolation linéaire au sein de l'étape pour le nombre de valeurs distinctes attendues, et reflète que deux points finaux de plage sont désormais spécifiés (et supposés exister au sein de l'étape d'histogramme) plutôt qu'un.

En utilisant les étapes de l'histogramme données dans la question:

étapes de l'histogramme

Pour la requête avec BETWEEN '20140615' AND '20140616', le calcul est:

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

... donnant 225,75 . Le passage @Q2de '20140616'à '20140617'donne un résultat de 250,833 .

Les deux résultats correspondent à ceux donnés dans la question.

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.