web-dev-qa-db-fra.com

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

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 assez 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 table AdventureWorks2014 base de données basée sur le prédicat de plage à l'aide de la colonne TransactionDate et de la plage de dates comprise entre '20140614' et '20140618'.

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

Histogram

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:

enter image description here

Selon la formule, il s'est avéré 150,5, mais l'optimiseur estime le prédicat à 225,75 lignes, et si vous modifiez 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?

13

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 de BETWEEN revient à écrire 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:

question histogram steps

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 . En changeant @Q2 de '20140616' à '20140617' donne un résultat de 250.833 .

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

13
Paul White 9