Come fa SQL Server a sapere che i predicati sono correlati?


15

Durante la diagnosi di query di SQL Server 2008 R2 con scarsa stima della cardinalità (nonostante l'indicizzazione semplice, statistiche aggiornate, ecc.) E quindi piani di query scarsi, ho trovato un articolo KB forse correlato: FIX: prestazioni scadenti quando si esegue una query che contiene predicati AND correlati in SQL Server 2008 o in SQL Server 2008 R2 o in SQL Server 2012

Posso immaginare cosa significhi l'articolo correlato con "correlato", ad esempio il predicato n. 2 e il predicato n. 1 sono in gran parte destinati alle stesse righe.

Ma non so come SQL Server sia a conoscenza di queste correlazioni. Una tabella necessita di un indice a più colonne contenente colonne di entrambi i predicati? SQL utilizza le statistiche per verificare se i valori di una colonna sono correlati a un'altra? Oppure viene utilizzato un altro metodo?

Lo sto chiedendo per due motivi:

  1. per determinare quali delle mie tabelle e query potrebbero essere migliorate utilizzando questo aggiornamento rapido
  2. per sapere cosa dovrei fare nell'indicizzazione, nelle statistiche, ecc. per influire sul numero 1

Risposte:


20

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

Piano di esecuzione predefinito

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 TransactionIDcolonna 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 TransactionDatedell'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 TransactionIDe TransactionDatehanno 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:

Piano post-esecuzione

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 TransactionIDsolo 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 ANDpredicati correlati . Ogni predicato è considerato per una possibile correlazione e ci sono altri aggiustamenti apportati quando ANDsono 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 TransactionDatecolonna.

DBCC SHOW_STATISTICS
    (
        'Production.TransactionHistory', 
        'stats Production.TransactionHistory TransactionDate TransactionID'
    );

Statici a più colonne

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:

Piano statistico a più colonne

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.