È possibile forzare l'ottimizzatore per eliminare le tabelle irrilevanti in questa vista partizionata?


22

Sto testando architetture diverse per tabelle di grandi dimensioni e un suggerimento che ho visto è di utilizzare una vista partizionata, per cui una tabella di grandi dimensioni viene suddivisa in una serie di tabelle più piccole "partizionate".

1 , 2 , 3 , 4

Nel testare questo approccio, ho scoperto qualcosa che per me non ha molto senso. Quando filtro su "colonna di partizionamento" nella vista dei fatti, l'ottimizzatore cerca solo nelle tabelle pertinenti. Inoltre, se filtro su quella colonna nella tabella delle dimensioni, l'ottimizzatore elimina le tabelle non necessarie.

Tuttavia, se filtro su qualche altro aspetto della dimensione, l'ottimizzatore cerca sul PK / CI di ogni tabella di base.

Ecco le domande in questione:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
    and o.ObservationDateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
    and od.DateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];

filtro dei fatti sulla chiave

filtro dim sul tasto

filtro fioco sull'aspetto

Ecco un collegamento alla sessione di SQL Sentry Plan Explorer.

Sto lavorando sul partizionamento della tabella più grande per vedere se ottengo l'eliminazione della partizione per rispondere in modo simile.

Ottengo l'eliminazione della partizione per la (semplice) query che filtra su un aspetto della dimensione.

Nel frattempo, ecco una copia solo delle statistiche del database:

https://gist.github.com/swasheck/9a22bf8a580995d3b2aa

Il "vecchio" stimatore della cardinalità ottiene un piano meno costoso, ma ciò è dovuto alle stime di cardinalità inferiori su ciascuna ricerca dell'indice (non necessaria).

Mi piacerebbe sapere se c'è un modo per ottenere l'ottimizzatore per utilizzare la colonna chiave quando si filtra da un altro aspetto della dimensione in modo che possa eliminare le ricerche su tabelle irrilevanti.

Versione di SQL Server:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)

Solo un FYI .. l'ultimo flusso di statistiche è danneggiatoCREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Kin Shah

Sembra che lo script per il database di sole statistiche sia troncato. Ho provato a fare clic su "Visualizza il file completo" e scaricare lo zip, ma in entrambi i casi non ho statistiche per la ObservationDatestabella. Non sto ottenendo lo stesso piano di Paul, nemmeno con il 4199, e penso che questo sia il motivo.
Geoff Patterson,

@GeoffPatterson funziona per me. hai fatto clic sul collegamento al file raw? gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw/… tuttavia, come notato da Kin, l'ultimo flusso di statistiche è corrotto: /
swasheck

Ho fatto clic sul collegamento per il file non elaborato. Lo script funziona (tranne il problema riscontrato da Kin), ma non contiene alcuna logica su cui creare statistiche ObservationDates. Ho finito per correre UPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000manualmente per ottenere il piano dimostrato da Paul.
Geoff Patterson,

dispari. creando un nuovo database ed eseguendo quello script ho degli oggetti stats (beh, sono indici), ObservationDatesquindi non sono sicuro di cosa stia succedendo. inoltre, non riesco nemmeno a generare il piano paul. proverò l'aggiornamento per vedere.
cambio

Risposte:


10

Abilita flag di traccia 4199.

Ho anche dovuto rilasciare:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

per ottenere i piani mostrati di seguito. Le statistiche per questa tabella mancavano dal caricamento. La cifra 73.049 proveniva dalle informazioni sulla cardinalità della tabella nell'allegato Plan Explorer. Ho usato SQL Server 2014 SP1 CU4 (build 12.0.4436) con due processori logici, memoria massima impostata su 2048 MB e nessun flag di traccia oltre a 4199.

Dovresti quindi ottenere un piano di esecuzione che prevede l'eliminazione dinamica della partizione:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where 
    od.[Year] >= 2000 and od.[Year] < 2006
group by 
    od.[Year]
option (querytraceon 4199);

Frammento del piano:

Frammento di piano

Questo potrebbe apparire peggio, ma i filtri sono tutti filtri di avvio . Un predicato di esempio è:

Proprietà del filtro

Per iterazione del loop, il predicato di avvio viene testato e solo se restituisce true viene eseguita la ricerca dell'indice cluster sotto di esso. Quindi, eliminazione dinamica delle partizioni.

Questo forse non è altrettanto efficace dell'eliminazione statica, specialmente se il piano è parallelo.

Potrebbe essere necessario provare i suggerimenti come MAXDOP 1, FAST 1o FORCESEEKsulla vista per ottenere lo stesso piano. Le scelte di costo dell'ottimizzatore con viste partizionate (come le tabelle partizionate) possono essere complicate.

Il punto è che è necessario un piano con filtri di avvio per ottenere l'eliminazione dinamica delle partizioni con viste partizionate.


Domande con USE PLANsuggerimenti incorporati : (tramite gist.github.com):


1
Grandi informazioni, grazie Paolo! Mi ero chiesto dopo aver scritto la mia risposta perché non esiste un modo in cui SQL Server possa fare questo tipo di eliminazione. Si scopre che c'è, non l'avevo mai visto prima!
Geoff Patterson,

6

La mia osservazione è sempre stata che è necessario specificare esplicitamente il valore (o l'intervallo di valori) per la colonna di partizione nella query per ottenere "eliminazione della tabella" in una vista partizionata. Questo si basa sull'esperienza nell'utilizzo di viste partizionate nella produzione da SQL Server 2000 a SQL Server 2014.

SQL Server non ha il concetto di un operatore di join loop in cui il motore può indirizzare dinamicamente la ricerca direttamente alla tabella corretta sul lato interno del loop in base al valore della riga sul lato esterno del loop. Tuttavia, come spiega la risposta di Paul , esiste la possibilità di un piano con filtri di avvio al fine di saltare dinamicamente tabelle irrilevanti sul lato interno del loop in tempo costante (al contrario del logaritmico eseguendo effettivamente la ricerca).

Si noti che per le tabelle partizionate, tuttavia, è supportato questo tipo di ricerca (verso una partizione specifica).

Se si è certi di utilizzare le viste partizionate, un'altra opzione è quella di dividere la query in più query, ad esempio:

-- Gather than the min/max values for the partition column
DECLARE @minDateKey INT,
        @maxDateKey INT
SELECT @minDateKey = MIN(DateKey),
        @maxDateKey = MAX(DateKey)
FROM dbo.ObservationDates od
WHERE od.[Year] >= 2000 and od.[Year] < 2006

-- Since I have a stats-only copy of the database, simulate having run the query above
-- (You can comment this out since you have the actual data.)
SELECT @minDateKey = 20000101, @maxDateKey = 20051231

-- Adjust the query to use the min/max values of the partition column
-- rather than filtering on a different column in the dimension table
select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
WHERE od.DateKey >= @minDateKey AND od.DateKey <= @maxDateKey
group by od.[Year]
-- Must use OPTION RECOMPILE; otherwise the plan will touch all tables because it
-- must do so in order to be valid for all values of the parameters!
OPTION (RECOMPILE)

Questo produce il seguente piano. Esiste ora una query aggiuntiva che raggiunge la tabella delle dimensioni, ma la query sulla tabella dei fatti (presumibilmente molto più grande) è ottimizzata.

inserisci qui la descrizione dell'immagine


Lo stesso effetto si otterrebbe se incorporassi la prima query nella seconda senza ricorrere alle variabili?
Andriy M,

@AndriyM Se ti sto capendo correttamente, la risposta è no, lo stesso effetto non sarà raggiunto e il piano di query toccherà tutte le tabelle nella vista partizionata se provi a combinare le due query. Se dovessi eseguire la prima query, quindi incollare i valori 20000101e 20051231invece le variabili (o fare qualcosa di simile tramite due query separate nella tua applicazione), quindi sì, lo stesso effetto sarebbe ottenuto senza usare le variabili.
Geoff Patterson,
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.