Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Perché Query Optimizer ignora totalmente gli indici di visualizzazione indicizzati?

tl;dr risposta:se non specifichi NOEXPAND, Query Optimizer non ha idea che stai inviando una semplice selezione da una vista. Dovrebbe corrispondere all'espansione della tua query (che è tutto ciò che vede) con un indice di visualizzazione. Probabilmente non si preoccuperà quando si tratta di un join a cinque con un mucchio di cast.

La corrispondenza dell'indice di visualizzazione a una query è un problema difficile e credo che la tua visualizzazione sia troppo complicata perché il motore di query corrisponda a un indice. Considera questa una delle tue domande:

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

È ovvio per te che questo può utilizzare un indice di visualizzazione, ma questa non è la query che vede il motore di query. Le visualizzazioni vengono espanse automaticamente se non specifichi NOEXPAND, quindi questo è ciò che va al motore di query:

SELECT ID, Code1 FROM (
    SELECT e.ID, 'NR'+CAST(c1.CODE as nvarchar(11)) as Code1, 'NR'+CAST(c2.CODE as nvarchar(11)) as Code2, 'NR'+CAST(c3.CODE as nvarchar(11)) as Code3, 'NR'+CAST(c4.CODE as nvarchar(11)) as Code4, 'NR'+CAST(c5.CODE as nvarchar(11)) as Code5
    FROM dbo.Entity e
        inner join  dbo.Classificator1 c1 on e.ID = c1.ID
        inner join  dbo.Classificator2 c2 on e.ID = c2.ID
        inner join  dbo.Classificator3 c3 on e.ID = c3.ID
        inner join  dbo.Classificator4 c4 on e.ID = c4.ID
        inner join  dbo.Classificator5 c5 on e.ID = c5.ID;
) AS V;

Il motore di query vede questa query complicata e contiene informazioni (ma probabilmente non SQL delle definizioni di visualizzazione) che descrivono gli indici di visualizzazione che sono stati definiti. Dato che questa query e gli indici di visualizzazione hanno entrambi più join e cast, la corrispondenza è un lavoro difficile.

Tieni presente che sai che i join e le corrispondenze sono identici in questa query e negli indici di visualizzazione, ma il Query Processor non lo sa. Tratta questa query esattamente come se fosse unita a cinque copie di Classificator3 o se una delle colonne fosse 'NQ'+CAST(c2.CODE as varchar(12)). Il matcher dell'indice di vista (supponendo che abbia fatto qualsiasi tentativo di abbinare questa query complicata) dovrebbe abbinare ogni dettaglio di questa query ai dettagli degli indici di vista sulle tabelle coinvolte.

Il motore di query ha come obiettivo n. 1 quello di trovare un modo per eseguire la query in modo efficiente. Probabilmente non è progettato per dedicare molto tempo a cercare di abbinare ogni dettaglio di un join a cinque vie e CAST a un indice di visualizzazione.

Se dovessi indovinare, sospetto che il matcher dell'indice di visualizzazione veda che le colonne dei risultati della query non sono nemmeno colonne di nessuna tabella sottostante (a causa del CAST) e semplicemente non si preoccupa di provare nulla. Aggiunto :Sbaglio. Ho appena provato il suggerimento di Martin di aggiornare le statistiche per rendere la query costosa e un indice di visualizzazione è stato abbinato per alcune di queste query senza NOEXPAND. Il View Matcher è più intelligente di quanto pensassi! Quindi il problema è che il view matcher probabilmente si sforza di trovare una corrispondenza con una query complicata se il suo costo è molto alto.

Usa l'hint NOEXPAND invece di aspettarti che il motore di query sia in grado di capire cosa corrisponde qui. NOEXPAND è assolutamente tuo amico, perché poi il motore di query può vedere

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

ed è quindi immediatamente evidente al matcher dell'indice di visualizzazione che esiste un indice utile.

(Nota:il tuo codice SQL Fiddle ha tutti e 5 i riferimenti di chiave esterna alla stessa tabella, che probabilmente non è quello che vuoi.)