Considera la semplice query AdventureWorks e il piano di esecuzione mostrati di seguito. La query contiene predicati connessi AND
. La stima della cardinalità dell'ottimizzatore è di 41.211 righe:
-- Estimate 41,211 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Utilizzo delle statistiche predefinite
Dato solo statistiche a colonna singola, l'ottimizzatore produce questa stima stimando la cardinalità per ciascun predicato separatamente e moltiplicando le selettività risultanti insieme. Questa euristica presuppone che i predicati siano completamente indipendenti.
La suddivisione della query in due parti semplifica la visualizzazione del calcolo:
-- Estimate 68,336.4 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336;
La tabella Cronologia transazioni contiene in totale 113.443 righe, quindi la stima 68.336,4 rappresenta una selettività di 68336,4 / 113443 = 0,60238533 per questo predicato. Questa stima si ottiene utilizzando le informazioni dell'istogramma per la TransactionID
colonna e i valori costanti specificati nella query.
-- Estimate 68,413 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Questo predicato ha una selettività stimata di 68413.0 / 113443 = 0.60306056 . Ancora una volta, viene calcolato dai valori costanti del predicato e dall'istogramma TransactionDate
dell'oggetto statistico.
Supponendo che i predicati siano completamente indipendenti, possiamo stimare la selettività dei due predicati insieme moltiplicandoli insieme. La stima della cardinalità finale si ottiene moltiplicando la selettività risultante per le 113.443 righe nella tabella di base:
0.60238533 * 0.60306056 * 113443 = 41210.987
Dopo l'arrotondamento, questa è la stima 41.211 vista nella query originale (l'ottimizzatore utilizza anche la matematica in virgola mobile internamente).
Non è una grande stima
Le colonne TransactionID
e TransactionDate
hanno una stretta correlazione nel set di dati AdventureWorks (come spesso fanno le chiavi e le colonne di data che aumentano monotonicamente). Questa correlazione significa che l'assunzione di indipendenza è violata. Di conseguenza, il piano di query post-esecuzione mostra 68.095 righe anziché le 41.211 stimate:
Traccia bandiera 4137
L'abilitazione di questo flag di traccia modifica l'euristica utilizzata per combinare i predicati. Invece di assumere la completa indipendenza, l'ottimizzatore ritiene che le selettività dei due predicati siano abbastanza vicine da poter essere correlate:
-- Estimate 68,336.4
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13'
OPTION (QUERYTRACEON 4137);
Ricordiamo che TransactionID
solo il predicato ha stimato 68.336,4 righe e il fileTransactionDate
solo predicato ha stimato 68.413 righe. L'ottimizzatore ha scelto la più bassa di queste due stime anziché moltiplicare le selettività.
Questa è solo una diversa euristica, ovviamente, ma può aiutare a migliorare le stime per le query con AND
predicati correlati . Ogni predicato è considerato per una possibile correlazione e ci sono altri aggiustamenti apportati quando AND
sono coinvolte molte clausole, ma questo esempio serve a mostrarne le basi.
Statistiche a più colonne
Questi possono aiutare nelle query con correlazioni, ma le informazioni sull'istogramma sono ancora basate esclusivamente sulla colonna principale delle statistiche. Le seguenti statistiche multi-colonna candidate pertanto differiscono in modo importante:
CREATE STATISTICS
[stats Production.TransactionHistory TransactionID TransactionDate]
ON Production.TransactionHistory
(TransactionID, TransactionDate);
CREATE STATISTICS
[stats Production.TransactionHistory TransactionDate TransactionID]
ON Production.TransactionHistory
(TransactionDate, TransactionID);
Prendendo solo uno di questi, possiamo vedere che l'unica informazione extra sono i livelli extra della densità 'all'. L'istogramma contiene ancora solo informazioni dettagliate sulla TransactionDate
colonna.
DBCC SHOW_STATISTICS
(
'Production.TransactionHistory',
'stats Production.TransactionHistory TransactionDate TransactionID'
);
Con queste statistiche multi-colonna in atto ...
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
... il piano di esecuzione mostra una stima esattamente uguale a quando erano disponibili solo le statistiche a colonna singola:
Statistics objects on multiple columns also store statistical information about the correlation of values among the columns