Perché l'operatore di concatenazione stima un numero di righe inferiore rispetto ai suoi input?


20

Nel seguente frammento del piano di query, sembra ovvio che la stima di riga per l' Concatenationoperatore dovrebbe essere ~4.3 billion rowso la somma delle stime di riga per i suoi due input.

Tuttavia, ~238 million rowsviene prodotta una stima , che porta a una strategia Sort/ subottimale Stream Aggregateche trasferisce centinaia di GB di dati in tempdb. Una stima logicamente coerente in questo caso avrebbe prodotto a Hash Aggregate, rimosso la fuoriuscita e migliorato notevolmente le prestazioni della query.

È un bug in SQL Server 2014? Vi sono circostanze valide in cui una stima inferiore agli input potrebbe essere ragionevole? Quali soluzioni alternative potrebbero essere disponibili?

inserisci qui la descrizione dell'immagine

Ecco il piano di query completo (anonimizzato). Non ho accesso sysadmin a questo server per fornire output da QUERYTRACEON 2363o flag di traccia simili, ma potrei essere in grado di ottenere questi output da un amministratore se fossero utili.

Il database è nel livello di compatibilità 120 e pertanto utilizza il nuovo stima della cardinalità di SQL Server 2014.

Le statistiche vengono aggiornate manualmente ogni volta che vengono caricati i dati. Dato il volume di dati, stiamo attualmente utilizzando la frequenza di campionamento predefinita. È possibile che una frequenza di campionamento più elevata (o FULLSCAN) possa avere un impatto.

Risposte:


21

Per citare Campbell Fraser su questo articolo Connect :

Queste "incongruenze di cardinalità" possono insorgere in diverse situazioni, anche quando si usa il concat. Possono sorgere perché la stima di una sottostruttura particolare nel piano finale potrebbe essere stata eseguita su una sottostruttura strutturata diversamente ma logicamente equivalente. A causa della natura statistica della stima della cardinalità, la stima su alberi diversi ma logicamente equivalenti non è garantita per ottenere la stessa stima. Quindi nel complesso non vengono fornite garanzie di coerenza attesa.

Per approfondire un po 'questo: il modo in cui mi piace spiegarlo è dire che la stima iniziale della cardinalità (eseguita prima dell'inizio dell'ottimizzazione basata sui costi) produce stime della cardinalità più "coerenti", poiché viene elaborato l'intero albero iniziale, con ogni successiva stima che dipende direttamente dalla precedente.

Durante l'ottimizzazione basata sui costi, parti dell'albero del piano (uno o più operatori) possono essere esplorate e sostituite con alternative, ognuna delle quali può richiedere una nuova stima della cardinalità. Non esiste un modo generale per dire quale stima sarà generalmente migliore di un'altra, quindi è del tutto possibile finire con un piano finale che appare "incoerente". Questo è semplicemente il risultato di ricucire "pezzi di piani" per formare la disposizione finale.

Detto questo, ci sono state alcune modifiche dettagliate al nuovo stimatore della cardinalità (CE) introdotto in SQL Server 2014 che rende questo un po ' meno comune rispetto al CE originale.

Oltre all'aggiornamento all'ultimo aggiornamento cumulativo e alla verifica che le correzioni dell'ottimizzatore con 4199 siano attive, le opzioni principali sono provare le modifiche statistiche / indice (notando gli avvisi per gli indici mancanti) e gli aggiornamenti, oppure esprimere la query in modo diverso. L'obiettivo è quello di acquisire un piano che mostri il comportamento richiesto. Questo può quindi essere bloccato con una guida di piano, per esempio.

Il piano anonimo rende difficile la valutazione dei dettagli, ma vorrei anche esaminare attentamente le bitmap per vedere se sono della varietà "ottimizzata" (Opt_Bitmap) o post-ottimizzazione (Bitmap). Sono anche sospettoso dei filtri.

Se i conteggi delle righe sono comunque accurati, questa sembra una query che potrebbe trarre vantaggio dall'archivio colonne. A parte i soliti vantaggi, potresti essere in grado di sfruttare la concessione di memoria dinamica per gli operatori in modalità batch ( potrebbe essere necessario il flag di traccia 9389 ).


7

La creazione di un banco di prova, piuttosto semplice, su SQL Server 2012 (11.0.6020) mi consente di ricreare un piano con due query con hash corrispondenti concatenate tramite a UNION ALL. Il mio banco di prova non visualizza la stima errata che vedi. Forse questo è un problema di SQL Server 2014 CE.

Ottengo una stima di 133.785 righe per una query che in realtà restituisce 280 righe, tuttavia è prevedibile, come vedremo più avanti in basso:

IF OBJECT_ID('dbo.Union1') IS NOT NULL
DROP TABLE dbo.Union1;
CREATE TABLE dbo.Union1
(
    Union1_ID INT NOT NULL
        CONSTRAINT PK_Union1
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , Union1_Text VARCHAR(255) NOT NULL
    , Union1_ObjectID INT NOT NULL
);

IF OBJECT_ID('dbo.Union2') IS NOT NULL
DROP TABLE dbo.Union2;
CREATE TABLE dbo.Union2
(
    Union2_ID INT NOT NULL
        CONSTRAINT PK_Union2
        PRIMARY KEY CLUSTERED
        IDENTITY(2,2)
    , Union2_Text VARCHAR(255) NOT NULL
    , Union2_ObjectID INT NOT NULL
);

INSERT INTO dbo.Union1 (Union1_Text, Union1_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;

INSERT INTO dbo.Union2 (Union2_Text, Union2_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;
GO

SELECT *
FROM dbo.Union1 u1
    INNER HASH JOIN sys.objects o ON u1.Union1_ObjectID = o.object_id
UNION ALL
SELECT *
FROM dbo.Union2 u2
    INNER HASH JOIN sys.objects o ON u2.Union2_ObjectID = o.object_id;

Penso che il motivo sia dovuto alla mancanza di statistiche per i due join risultanti che sono UNIONed. SQL Server deve fare ipotesi ponderate nella maggior parte dei casi sulla selettività delle colonne di fronte alla mancanza di statistiche.

Joe Sack ha una lettura interessante su questo qui .

Per un UNION ALL, è sicuro dire che vedremo esattamente il numero totale di righe restituite da ciascun componente dell'unione, tuttavia poiché SQL Server sta usando le stime di riga per i due componenti di UNION ALL, vediamo che aggiunge il totale delle righe stimate da entrambi richieste per elaborare il preventivo per l'operatore di concatenazione.

Nel mio esempio sopra, il numero stimato di righe per ogni porzione di UNION ALLè 66.8927, che quando sommato è pari a 133.785, che vediamo per il numero stimato di righe per l'operatore di concatenazione.

Il piano di esecuzione effettivo per la query del sindacato sopra è simile a:

inserisci qui la descrizione dell'immagine

È possibile visualizzare il numero di righe "stimato" vs "effettivo". Nel mio caso, l'aggiunta del numero "stimato" di righe restituite dai due operatori di corrispondenza hash equivale esattamente all'importo mostrato dall'operatore di concatenazione.

Vorrei provare a ottenere output dalla traccia 2363 ecc. Come raccomandato nel post di Paul White che mostri nella tua domanda. In alternativa, è possibile provare a utilizzare OPTION (QUERYTRACEON 9481)la query per ripristinare la versione 70 CE per vedere se "risolve" il problema.


1
Grazie. Ho sicuramente visto che "la ragione sta nella mancanza di statistiche per i due join risultanti che sono UNIONed" hanno un grande impatto sui successivi join o aggregazioni (che si verificano dopo l'UNION). SQL 2014 in realtà gestisce questo meglio di SQL 2012 nella mia esperienza. Ecco un semplice script di test che ho usato in passato, ad esempio: gist.github.com/anonymous/1497112d8b25ab8fb782a04569959c68 Tuttavia, non penso che un operatore di concatenazione avrebbe bisogno dello stesso tipo di informazioni sulla distribuzione dei valori che un join potrebbe aver bisogno.
Geoff Patterson,

Concordo con te sul fatto che la concatenazione non dovrebbe richiedere statistiche per funzionare correttamente. Dovrebbe semplicemente essere in grado di aggiungere in modo affidabile le stime delle righe in entrata per avere una buona idea del numero di righe che produrrà. Come mostra @PaulWhite nella sua risposta, sorprendentemente non è sempre il caso. Per me il takeaway qui può sembrare semplice, ma in realtà potrebbe non esserlo. Sono davvero contento che tu abbia posto la domanda nel modo in cui l'hai fatto, vorrei solo che non avessi dovuto anonimizzare il piano: sarebbe stato interessante vedere la domanda vera e propria.
Max Vernon,
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.