2017-02-10 6 views
2

Ich habe eine Aussage, die 10 Sekunden auszuführen auf 10k Artikel in der Tabelle X nimmt:Warum ist meine unkorrelierte Unterabfrage so langsam?

Version 1

SELECT * 
FROM X 
WHERE pk = 77843 
    AND (a IS NULL OR a NOT IN (SELECT DISTINCT(b) 
           FROM X 
           WHERE pk = 77843 
           AND l IS NOT NULL)) 

Die Unterabfrage unkorreliert ist, was bedeutet, dass es zu keinen Bezug hat die äußere Abfrage. Dies bedeutet, dass die Unterabfrage nur einmal ausgeführt werden sollte.

Version 2:

Nun, wenn ich die Unterabfrage und führen die Berechnung extrahieren vorab die Abfrage in < 1s führt.

DECLARE @listOfb table (id int) 

INSERT INTO @listOfb(id) 
    (SELECT DISTINCT(b) as Numbers 
    FROM X 
    WHERE pk = 77843 
     AND l IS NOT NULL) 

SELECT * 
FROM X 
WHERE pk = 77843 
    AND (a IS NULL OR a NOT IN (SELECT * FROM @listOfb)) 

Warum ist die Version 2 so viel schneller als Version 1?

aktualisieren

ich hinzugefügt haben 1 ein Ausführungsplan von Version (was ich denke, genannt wird): Die Abfrage um 10k Löschen von Zeilen ist.

enter image description here

+3

Haben Sie sich die ** Ausführungspläne ** für die beiden Abfragen angesehen? –

+0

'DISTINCT' ist keine Funktion (in einer Spalte), sie ist Teil von' SELECT DISTINCT' und arbeitet mit den ganzen ausgewählten Zeilen. Entfernen Sie diese überflüssigen Klammern, um die Dinge klarer zu machen! 'SELECT DISTINCT (a), b ...' ist besser geschrieben als 'SELECT DISTINCT a, b ...', kann aber auch geschrieben werden als 'SELECT DISTINCT a, (b) ...' ... – jarlh

+1

, keine Notwendigkeit, SELECT DISTINCT hier zu tun ... – jarlh

Antwort

1

Versuchen mit einer Common Table Expression und einer UNION:

;WITH CTE 
AS 
(
    SELECT * 
    FROM X 
    WHERE pk = 77843 
) 
SELECT * 
FROM CTE 
WHERE a IS NULL 
UNION ALL 
SELECT * 
FROM CTE C1 
WHERE a IS NOT NULL AND 
     NOT EXISTS (SELECT * FROM CTE C2 WHERE C1.a = C2.b AND l IS NULL) 
+1

Es besteht keine Notwendigkeit für die erste Auswahl, "NOT EXISTS" gibt Zeilen mit NULL in "a" zurück. – dnoeth

1

Sie einen Blick auf diese article

haben sollte ich die gleichen Server-Version nicht haben, aber was ich würde versuchen, das 'von x' auf der Hauptabfrage aber auch auf der Unterabfrage freizugeben.

SELECT * 
FROM X (NOLOCK) 
WHERE pk = 77843 

Von meiner kleinen Erfahrung, hängt von der Tabellengröße und die Indizes auf sich, fand ich manchmal Unterschied der Leistung während zweimal die gleiche Tabelle abfragt (vor allem mit dem gleichen Zustand ‚pk = 77843‘ und/oder Aktualisierung/Löschen von Operationen).

Über Ihren letzten Kommentar. Ich sehe nicht aus dem Ausführungsplan, wo die Unterabfrage mehr als einmal ausgeführt wird. Meiner Meinung nach sperrt der erste index_seek die PK-Spalte [Hauptabfrage] und wenn kommt die zweite index_seek [Unterabfrage] auf der gleichen Spalte (ich denke, weil ich nicht alle Details aus Ihrem Screenshot sehen kann) das verursacht ein Leistungsproblem.

Aber Ursache davon, haben Sie eine bessere Leistung, wenn Sie diese zwei Abfragen (mit fast den gleichen Bedingungen) separat durchführen.