Ho avuto questo problema molto tempo fa, ho trovato una soluzione alternativa che mi andava bene e me ne sono dimenticato.
Ma ora c'è questa domanda su SO, quindi sono disposto a sollevare questo problema.
C'è una vista che unisce alcune tabelle in modo molto semplice (ordini + righe ordine).
Quando viene eseguita una query senza una where
clausola, la vista restituisce diversi milioni di righe.
Tuttavia, nessuno lo chiama mai così. La solita domanda è
select * from that_nasty_view where order_number = 123456;
Questo restituisce circa 10 record su 5m.
Una cosa importante: la vista contiene una funzione di finestra rank()
, che è partizionata esattamente dal campo in cui viene sempre interrogata la vista:
rank() over (partition by order_number order by detail_line_number)
Ora, se questa vista viene interrogata con parametri letterali nella stringa di query, esattamente come mostrato sopra, restituisce immediatamente le righe. Il piano di esecuzione va bene:
- Ricerca indice su entrambe le tabelle utilizzando gli indici su
order_number
(restituisce 10 righe). - Calcolo delle finestre sul risultato minuscolo restituito.
- Selezione.
Tuttavia, quando la vista viene chiamata in modo parametrizzato, le cose diventano cattive:
Index scan
su tutte le tabelle ignorando gli indici. Restituisce 5m righe.- Enorme join.
- Calcolo di tutte le finestre
partition
(circa 500.000 finestre). Filter
per prendere 10 file su 5m.- Selezionare
Ciò accade in tutti i casi in cui sono coinvolti parametri. Può essere SSMS:
declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;
Può essere un client ODBC, come Excel:
select * from that_nasty_view where order_number = ?
Oppure può essere qualsiasi altro client che utilizza parametri e non concatenazione sql.
Se la funzione finestra viene rimossa dalla vista, viene eseguita perfettamente rapidamente, indipendentemente dal fatto che venga eseguita una query con i parametri.
La mia soluzione era rimuovere la funzione offensiva e riapplicarla in un secondo momento.
Ma cosa dà? È davvero un bug nel modo in cui SQL Server 2008 gestisce le funzioni della finestra?
order_number
non è una chiave primaria. È int not null
con indice non cluster su di esso in entrambe le tabelle.
OPTION (RECOMPILE)
aiuto?