Frage

Wenn ich eine Anfrage habe wie:

Select EmployeeId 
From Employee 
Where EmployeeTypeId IN (1,2,3)

und ich habe einen Index dazu EmployeeTypeId Feld, verwendet SQL Server diesen Index immer noch?

War es hilfreich?

Lösung

Ja das ist richtig.Wenn Ihre Mitarbeitertabelle 10.000 Datensätze enthält und nur 5 Datensätze die Mitarbeitertyp-ID in (1,2,3) haben, wird höchstwahrscheinlich der Index zum Abrufen der Datensätze verwendet.Wenn jedoch festgestellt wird, dass 9.000 Datensätze den EmployeeIDType in (1,2,3) haben, würde es höchstwahrscheinlich nur einen Tabellenscan durchführen, um die entsprechenden EmployeeIDs zu erhalten, da es schneller ist, die gesamte Tabelle durchzugehen, als zu ihr zu gehen Durchsuchen Sie jeden Zweig des Indexbaums und betrachten Sie die Datensätze einzeln.

SQL Server unternimmt viele Dinge, um die Ausführung der Abfragen zu optimieren.Manchmal gibt es jedoch nicht die richtige Antwort.Wenn Sie wissen, dass SQL Server den Index nicht verwendet, können Sie durch einen Blick auf den Ausführungsplan im Abfrageanalysator die Abfrage-Engine mit der folgenden Änderung an Ihrer Abfrage anweisen, einen bestimmten Index zu verwenden.

Select EmployeeId From Employee WITH (Index(Index_EmployeeTypeId )) Where EmployeeTypeId IN (1,2,3)

Angenommen, der Index, den Sie für das Feld „EmployeeTypeId“ haben, heißt „Index_EmployeeTypeId“.

Andere Tipps

Normalerweise ist dies der Fall, es sei denn, die IN-Klausel deckt zu viel von der Tabelle ab, und dann wird ein Tabellenscan durchgeführt.Der beste Weg, dies in Ihrem speziellen Fall herauszufinden, besteht darin, es im Abfrageanalysator auszuführen und den Ausführungsplan zu überprüfen.

Sofern sich die Technologie in letzter Zeit nicht auf eine Weise verbessert hat, die ich mir nicht vorstellen kann, wird die angezeigte „IN“-Abfrage ein Ergebnis liefern, das im Grunde die ODER-Verknüpfung von drei Ergebnismengen ist, eine für jeden der Werte in der „IN“-Liste.Die IN-Klausel wird zu einer Gleichheitsbedingung für jede Liste und verwendet gegebenenfalls einen Index.Bei eindeutigen IDs und einer ausreichend großen Tabelle würde ich erwarten, dass der Optimierer einen Index verwendet.

Wenn die Elemente in der Liste jedoch nicht eindeutig wären und ich im Beispiel vermute, dass eine „TypeId“ ein Fremdschlüssel ist, dann interessiert mich mehr die Verteilung.Ich frage mich, ob der Optimierer die Statistiken für jeden Wert in der Liste überprüft.Angenommen, es überprüft den ersten Wert und stellt fest, dass er sich in 20 % der Zeilen befindet (einer Tabelle, die groß genug ist, um von Bedeutung zu sein).Es wird wahrscheinlich ein Tabellenscan sein.Aber wird für die anderen beiden derselbe Abfrageplan verwendet, auch wenn sie einzigartig sind?

Es ist wahrscheinlich umstritten – so etwas wie eine Employee-Tabelle ist wahrscheinlich klein genug, dass sie im Speicher zwischengespeichert bleibt, und Sie würden wahrscheinlich sowieso keinen Unterschied zwischen dieser Tabelle und dem indizierten Abruf bemerken.

Und schließlich, während ich predige, achten Sie auf die Abfrage in der IN-Klausel:Es ist oft eine schnelle Möglichkeit, etwas zum Laufen zu bringen, und kann (zumindest für mich) eine gute Möglichkeit sein, die Anforderung auszudrücken, aber es ist fast immer besser, es als Join umzuformulieren.Ihr Optimierer ist vielleicht schlau genug, dies zu erkennen, vielleicht aber auch nicht.Wenn Sie derzeit keine Leistungsprüfung anhand der Produktionsdatenmengen durchführen, tun Sie dies. In der heutigen Zeit der kostenbasierten Optimierung können Sie sich über den Abfrageplan erst dann sicher sein, wenn Sie über eine vollständige Auslastung und repräsentative Statistiken verfügen.Wenn nicht, dann seien Sie auf Überraschungen in der Produktion gefasst ...

Es besteht also das Potenzial, dass eine "in" -Klausel einen Tischscan ausführt, aber der Optimierer wird versuchen, den besten Weg zu erarbeiten, um damit umzugehen?

Ob ein Index verwendet wird, hängt nicht so sehr von der Art der Abfrage ab, sondern vielmehr von der Art und Verteilung der Daten in den Tabellen, der Aktualität Ihrer Tabellenstatistiken und dem tatsächlichen Datentyp der Spalte .

Die anderen Poster haben Recht, dass ein Index über einem Tabellenscan verwendet wird, wenn:

  • Die Abfrage greift nicht auf mehr als einen bestimmten Prozentsatz der indizierten Zeilen zu (sagen wir etwa 10 %, sollte aber je nach DBMS variieren).
  • Wenn es viele Zeilen, aber relativ wenige eindeutige Werte in der Spalte gibt, kann es alternativ auch schneller sein, einen Tabellenscan durchzuführen.

Die andere Variable, die möglicherweise nicht so offensichtlich ist, besteht darin, sicherzustellen, dass die Datentypen der verglichenen Werte gleich sind.Ich glaube nicht, dass in PostgreSQL Indizes verwendet werden, wenn Sie nach einer Gleitkommazahl filtern, Ihre Spalte jedoch aus Ganzzahlen besteht.Es gibt auch einige Operatoren, die die Indexverwendung nicht unterstützen (in PostgreSQL sieht der ILIKE-Operator wiederum so aus).

Wie bereits erwähnt, überprüfen Sie im Zweifelsfall immer den Abfrageanalysator und die Dokumentation Ihres DBMS ist Ihr Freund.

@Mike:Danke für die ausführliche Analyse.Es gibt auf jeden Fall einige interessante Punkte, die Sie da ansprechen.Das von mir gepostete Beispiel ist etwas trivial, aber die Grundlage der Frage war die Verwendung von NHibernate.

Mit NHibernate können Sie eine Klausel wie diese schreiben:

int[] employeeIds = new int[]{1, 5, 23463, 32523};
NHibernateSession.CreateCriteria(typeof(Employee))
.Add(Restrictions.InG("EmployeeId",employeeIds))

NHibernate generiert dann eine Abfrage, die wie folgt aussieht:

select * from employee where employeeid in (1, 5, 23463, 32523)

Wie Sie und andere bereits betont haben, sieht es so aus, als ob es Zeiten geben wird, in denen ein Index verwendet wird oder ein Tabellenscan stattfindet, aber das können Sie erst zur Laufzeit wirklich feststellen.

Select EmployeeId From Employee USE(INDEX(EmployeeTypeId))

Diese Abfrage durchsucht den von Ihnen erstellten Index.Für mich geht das.Bitte versuchen Sie es..

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top