2009-08-06 3 views
4

Ich habe vor einiger Zeit von einem DBA-Freund einen Trick gelernt, um bestimmte SQL-Abfragen zu beschleunigen. Ich erinnere mich, dass er erwähnt hat, dass es etwas damit zu tun hat, wie SQL Server die Abfrage kompiliert und dass der Abfragepfad gezwungen ist, den indizierten Wert zu verwenden.Warum beschleunigt dies meine SQL-Abfrage?

Hier ist meine ursprüngliche Abfrage ist (dauert 20 Sekunden):

select Part.Id as PartId, Location.Id as LocationId 
FROM Part, PartEvent PartEventOuter, District, Location 
WHERE 
    PartEventOuter.EventType = '600' AND PartEventOuter.AddressId = Location.AddressId 
    AND Part.DistrictId = District.Id AND Part.PartTypeId = 15 
    AND District.SubRegionId = 11 AND PartEventOuter.PartId = Part.Id 
    AND PartEventOuter.EventDateTime <= '4/28/2009 4:30pm' 
    AND NOT EXISTS (
      SELECT PartEventInner.EventDateTime 
      FROM PartEvent PartEventInner 
      WHERE PartEventInner.PartId = PartEventOuter.PartId 
       AND PartEventInner.EventDateTime > PartEventOuter.EventDateTime 
       AND PartEventInner.EventDateTime <= '4/30/2009 4:00pm') 

Hier wird die "optimierte" Abfrage ist (weniger als 1 Sekunde):

select Part.Id as PartId, Location.Id as LocationId 
FROM Part, PartEvent PartEventOuter, District, Location 
WHERE 
    PartEventOuter.EventType = '600' AND PartEventOuter.AddressId = Location.AddressId 
    AND Part.DistrictId = District.Id AND Part.PartTypeId = 15 
    AND District.SubRegionId = 11 AND PartEventOuter.PartId = Part.Id 
    AND PartEventOuter.EventDateTime <= '4/28/2009 4:30pm' 
    AND NOT EXISTS (
      SELECT PartEventInner.EventDateTime 
      FROM PartEvent PartEventInner 
      WHERE PartEventInner.PartId = PartEventOuter.PartId 
       **AND EventType = EventType** 
       AND PartEventInner.EventDateTime > PartEventOuter.EventDateTime 
       AND PartEventInner.EventDateTime <= '4/30/2009 4:00pm') 

im Detail, warum das jemand erklären, läuft so viel schneller? Ich versuche nur, das besser zu verstehen.

+2

Haben Sie versucht, den Abfrageplan zu betrachten? –

+0

Weil es einen Index für den Ereignistyp gibt? –

+0

Haben Sie keinen Index für dieses Feld? –

Antwort

3

wahrscheinlich, weil Sie ein Kartesisches Produkt erhalten, ohne Ihre Eventtype = Eventtype

von wikipedia: http://en.wikipedia.org/wiki/SQL

„[SQL] macht es zu einfach ein cartesianischen join (Verbindung aller möglichen Kombinationen) zu tun, die führt zu "Run-away" -Ergebnissätzen, wenn WHERE-Klauseln falsch eingegeben werden. Kartesische Joins werden in der Praxis so selten verwendet, dass ein explizites CARTESIAN-Schlüsselwort gerechtfertigt sein kann. (SQL 1992 führte das Schlüsselwort CROSS JOIN ein, das dem Benutzer klar macht, dass a Cartesian Join ist beabsichtigt, aber die Kurzschrift "Komma-Join" ohne Prädikat ist immer noch akzeptable Syntax, die immer noch den gleichen Fehler einleitet.) "

Sie durchlaufen tatsächlich mehr Zeilen als notwendig mit Ihrer ersten Abfrage.

http://www.fluffycat.com/SQL/Cartesian-Joins/

+0

Kann nicht sein ... Es gibt kein Tabellenqualifikationsmerkmal für EventType, daher wird es mit sich selbst verglichen. Im Wesentlichen ein No-Op (außer für NULL, das ist). –

+0

In meinen ersten Versuchen, diese Abfrage zu optimieren, habe ich tatsächlich alles in (linke) innere Verknüpfungen in den verwandten Feldern konvertiert. Dies hatte jedoch keinen Einfluss auf die Ausführungszeit eines Bits. – Keith

0

Odd, haben Sie einen Index mit sowohl EventType und EventDateTime darin definiert haben?

Edit:
warten, ist eine Eventtype Nullable-Spalte? Column = Column wird zu FALSE * ausgewertet, wenn der Wert NULL ist. Zumindest unter Verwendung der Standardeinstellungen von SQL Server. Das sicherere Äquivalent wäre EventType IS NOT NULL. Sehen Sie es, das das gleiche Ergebnis in Bezug auf die Geschwindigkeit ergibt?


*: Meine T-SQL-Referenz sagt es TRUE mit ANSI_NULLS Satz OFF bewerten soll, aber meine Abfragefenster etwas anderes sagt. * jetzt konfus *.
Irgendwelche Entscheidung? TRUE, FALSE, NULL oder UNKNOWN? :) Gotta love ‚binary‘ Logik in SQL :(

+0

Keine Indizes in den Spalten der PartEvent-Ansicht (in den Tabellen, aus denen die Ansicht stammt) – Keith

+0

Muss "EventType IS NOT NULL" versuchen, wenn ich zur Arbeit zurückkomme Montag – Keith

+0

Checking EventType IS NOT NULL hat die Abfrage nicht beschleunigt - es sind immer noch 20 Sekunden. Überprüfen, ob EventType = EventType immer noch <1 Sekunde dauert. – Keith

0

SQL Server verwendet einen Index-Lookup, wenn und nur wenn alle Spalten dieses Index sind in der Abfrage.

0

Jede nicht-indizierte Spalte einer Tabelle hinzufügen, führt Wenn Sie Ihre Abfrage zu einem früheren Zeitpunkt in Ihrer WHERE-Klausel einschränken, werden nachfolgende Scans schneller ausgeführt.Wenn Sie einen Indexscan hinzufügen, werden Ihre Tabellenscans mit weniger Daten ausgeführt

1

Gibt es eine große Anzahl von Datensätzen mit EventType = Null ?
Bevor Sie die zusätzliche Einschränkung hinzugefügt haben, hätte Ihre Unterabfrage alle Null-Datensätze zurückgegeben, die dann von dem Prädikat Nicht vorhanden für jede Zeile in der äußeren Abfrage gescannt werden müssten ... Je mehr Sie einschränken, was die Unterabfrage zurückgibt Je weniger Zeilen gescannt werden müssen, um das Nicht vorhanden zu überprüfen ...

Wenn dies der Fall ist, wäre es wahrscheinlich noch schneller, wenn Sie die Datensätze in der Unterabfrage ebenfalls auf EventType = '600' beschränken würden ....

Select Part.Id as PartId, Location.Id as LocationId 
FROM Part, PartEvent PartEventOuter, District, Location 
WHERE PartEventOuter.EventType = '600' 
    AND PartEventOuter.AddressId = Location.AddressId  
    AND Part.DistrictId = District.Id 
    AND Part.PartTypeId = 15  
    AND District.SubRegionId = 11 
    AND PartEventOuter.PartId = Part.Id  
    AND PartEventOuter.EventDateTime <= '4/28/2009 4:30pm'  
    AND NOT EXISTS (SELECT PartEventInner.EventDateTime     
        FROM PartEvent PartEventInner 
        WHERE PartEventInner.PartId = PartEventOuter.PartId 
         AND EventType = '600'       
         AND PartEventInner.EventDateTime > PartEventOuter.EventDateTime 
         AND PartEventInner.EventDateTime <= '4/30/2009 4:00pm') 
+0

Das ist genauso schnell, aber falsch für unsere Ergebnismenge ... Die Unterabfrage ist korrekt wie sie war (jeder "EventType") – Keith

0

Diese Art von Ding war früher viel häufiger als es jetzt ist. Oracle 6 war zum Beispiel empfindlich gegenüber der Reihenfolge, in der Sie Einschränkungen in den WHERE-Klauseln platziert haben. Der Grund, warum Sie überrascht sind, liegt darin, dass wir so gut darin sind, zu erwarten, dass die DB-Engine immer den besten Zugriffspfad ausarbeitet, egal wie Sie Ihr SQL strukturieren. Oracle 6 & 7 (Ich wechselte danach zu MSSQL) hatte auch die Hinweiserweiterung, mit der Sie der Datenbank mitteilen konnten, wie sie den Abfrageplan erstellen könnte. In diesem speziellen Fall ist es schwierig, eine schlüssige Antwort zu geben, ohne die tatsächlichen Abfragepläne zu sehen, aber ich vermute den Unterschied, dass Sie einen zusammengesetzten Index haben, der EventType verwendet, der nicht für die erste Abfrage, sondern für die zweite verwendet wird. Dies wäre ungewöhnlich, dass ich Ihre erste Abfrage es trotzdem verwendet haben erwarten würde, so vermute ich, dass die Datenbankstatistiken veraltet sein können, so

REGENERATE STATISTIK

dann versuchen Sie es erneut und Post Die Ergebnisse hier.