Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Warum ignoriert der Abfrageoptimierer Indizes für indizierte Ansichten vollständig?

tl;dr Antwort:Wenn Sie NOEXPAND nicht angeben, hat der Abfrageoptimierer keine Ahnung, dass Sie eine einfache Auswahl aus einer Ansicht übermitteln. Es müsste die Erweiterung Ihrer Abfrage (die alles ist, was es sieht) mit einem Ansichtsindex abgleichen. Wird wahrscheinlich nicht stören, wenn es sich um eine Fünf-Wege-Verbindung mit einer Reihe von Besetzungen handelt.

Das Anzeigen des Indexabgleichs mit einer Abfrage ist ein schwieriges Problem, und ich glaube, Ihre Ansicht ist zu kompliziert, als dass die Abfrage-Engine sie mit einem Index abgleichen könnte. Betrachten Sie diese eine Ihrer Abfragen:

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

Es ist offensichtlich, dass dies einen Ansichtsindex verwenden kann, aber dies ist nicht die Abfrage, die die Abfrage-Engine sieht. Ansichten werden automatisch erweitert, wenn Sie NOEXPAND nicht angeben, also geht Folgendes an die Abfrage-Engine:

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;

Die Abfrage-Engine erkennt diese komplizierte Abfrage und verfügt über Informationen (jedoch wahrscheinlich nicht über SQL von Ansichtsdefinitionen), die definierte Ansichtsindizes beschreiben. Angesichts der Tatsache, dass diese Abfrage und die Ansichtsindizes beide mehrere Joins und Casts haben, ist der Abgleich eine harte Arbeit.

Denken Sie daran, dass Sie wissen, dass die Verknüpfungen und Übereinstimmungen in dieser Abfrage und den Ansichtsindizes identisch sind, der Abfrageprozessor dies jedoch nicht weiß. Es behandelt diese Abfrage genau so, als ob sie fünf Kopien von Classificator3 hinzugefügt hätte oder wenn eine der Spalten 'NQ'+CAST(c2.CODE as varchar(12)) wäre. Der View-Index-Matcher (vorausgesetzt, er hat versucht, diese komplizierte Abfrage abzugleichen) müsste jedes Detail dieser Abfrage mit den Details der View-Indizes der beteiligten Tabellen abgleichen.

Das wichtigste Ziel der Abfrage-Engine ist es, einen Weg zu finden, um die Abfrage effizient auszuführen. Es ist wahrscheinlich nicht darauf ausgelegt, viel Zeit damit zu verbringen, jedes Detail eines Fünf-Wege-Joins und CASTs mit einem Ansichtsindex abzugleichen.

Wenn ich raten müsste, vermute ich, dass der Ansichtsindex-Matcher sieht, dass die Ergebnisspalten der Abfrage nicht einmal Spalten einer zugrunde liegenden Tabelle sind (wegen CAST) und sich einfach nicht die Mühe macht, irgendetwas zu versuchen. Hinzugefügt :Ich liege falsch. Ich habe gerade Martins Vorschlag ausprobiert, Statistiken zu aktualisieren, um die Abfrage teuer zu machen, und ein Ansichtsindex wurde für einige dieser Abfragen ohne NOEXPAND abgeglichen. Der View Matcher ist schlauer als ich dachte! Das Problem ist also, dass der View-Matcher wahrscheinlich mehr versucht, eine komplizierte Abfrage abzugleichen, wenn die Kosten sehr hoch sind.

Verwenden Sie den NOEXPAND-Hinweis, anstatt zu erwarten, dass die Abfrage-Engine herausfinden kann, was hier übereinstimmt. NOEXPAND ist absolut Ihr Freund, denn dann bekommt die Abfragemaschine zu sehen

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

und es ist dann für den View-Index-Matcher sofort offensichtlich, dass es einen nützlichen Index gibt.

(Hinweis:Ihr SQL-Fiddle-Code hat alle 5 Fremdschlüsselverweise auf dieselbe Tabelle, was wahrscheinlich nicht das ist, was Sie wollen.)