I piani di query con filtri bitmap possono talvolta essere difficili da leggere. Da l'articolo BOL per i flussi partiziona (sottolineatura mia):
L'operatore Repartition Streams consuma più flussi e produce più flussi di record. Il contenuto e il formato del record non vengono modificati. Se Query Optimizer utilizza un filtro bitmap, il numero di righe nel flusso di output viene ridotto.
Inoltre, è utile anche un articolo sui filtri bitmap:
Quando si analizza un piano di esecuzione contenente il filtro bitmap, è importante capire come i dati scorrono attraverso il piano e dove viene applicato il filtro. Il filtro bitmap e la bitmap ottimizzata vengono creati sul lato input di compilazione (tabella delle dimensioni) di un join hash; tuttavia, il filtraggio effettivo viene in genere eseguito all'interno dell'operatore Parallelism, che si trova sul lato di input della sonda (la tabella dei fatti) del join hash. Tuttavia, quando il filtro bitmap si basa su una colonna intera, il filtro può essere applicato direttamente alla tabella iniziale o all'operazione di scansione dell'indice anziché all'operatore Parallelismo. Questa tecnica si chiama ottimizzazione nella riga.
Credo sia quello che stai osservando con la tua domanda. È possibile elaborare una demo relativamente semplice per mostrare un operatore di flussi di ripartizione che riduce una stima di cardinalità, anche quando l'operatore bitmap è in IN_ROW
contrasto con la tabella dei fatti. Preparazione dati:
create table outer_tbl (ID BIGINT NOT NULL);
INSERT INTO outer_tbl WITH (TABLOCK)
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values;
create table inner_tbl_1 (ID BIGINT NULL);
create table inner_tbl_2 (ID BIGINT NULL);
INSERT INTO inner_tbl_1 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
INSERT INTO inner_tbl_2 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Ecco una query che non dovresti eseguire:
SELECT *
FROM outer_tbl o
INNER JOIN inner_tbl_1 i ON o.ID = i.ID
INNER JOIN inner_tbl_2 i2 ON o.ID = i2.ID
OPTION (HASH JOIN, QUERYTRACEON 9481, QUERYTRACEON 8649);
Ho caricato il piano . Dai un'occhiata all'operatore vicino inner_tbl_2
:
Puoi anche trovare utile il secondo test in Hash Joins on Nullable Columns di Paul White.
Ci sono alcune incongruenze nel modo in cui viene applicata la riduzione delle righe. Sono stato in grado di vederlo solo in un piano con almeno tre tavoli. Tuttavia, la riduzione delle righe previste sembra ragionevole con la giusta distribuzione dei dati. Supponiamo che la colonna unita nella tabella dei fatti abbia molti valori ripetuti che non sono presenti nella tabella delle dimensioni. Un filtro bitmap potrebbe eliminare quelle righe prima che raggiungano il join. Per la tua query la stima è ridotta completamente a 1. Il modo in cui le righe sono distribuite nella funzione hash fornisce un buon suggerimento:
Sulla base di ciò, ho il sospetto che tu abbia molti valori ripetuti per la Object1.Column21
colonna. Se le colonne ripetute non si trovano nell'istogramma delle statistiche per Object4.Column19
allora SQL Server potrebbe sbagliare la stima della cardinalità.
Penso che dovresti preoccuparti del fatto che potrebbe essere possibile migliorare le prestazioni della query. Naturalmente, se la query soddisfa i tempi di risposta o i requisiti SLA, potrebbe non valere la pena indagare ulteriormente. Tuttavia, se desideri indagare ulteriormente, ci sono alcune cose che puoi fare (oltre all'aggiornamento delle statistiche) per farti un'idea se lo Strumento per ottimizzare le query sceglierebbe un piano migliore se avesse informazioni migliori. È possibile inserire i risultati del join tra Database1.Schema1.Object10
e Database1.Schema1.Object11
in una tabella temporanea e vedere se si continuano a ottenere join loop nidificati. È possibile modificare tale join in a in LEFT OUTER JOIN
modo che Query Optimizer non riduca il numero di righe in quel passaggio. È possibile aggiungere un MAXDOP 1
suggerimento alla query per vedere cosa succede. Puoi usareTOP
insieme a una tabella derivata per forzare l'ultimo join, oppure è possibile anche commentare il join dalla query. Spero che questi suggerimenti siano sufficienti per iniziare.
Per quanto riguarda l' elemento di connessione nella domanda, è estremamente improbabile che sia correlato alla tua domanda. Tale problema non ha a che fare con stime di righe scadenti. Ha a che fare con una condizione di competizione in parallelismo che causa l'elaborazione di troppe righe nel piano di query dietro le quinte. Qui sembra che la tua query non stia facendo alcun lavoro extra.