Wie bereits in den Kommentaren angegeben, scheint es, als müssten Sie Ihre Statistiken aktualisieren.
Die geschätzte Anzahl der Zeilen aus dem kommenden Verbindung zwischen location
und testruns
ist enorm unterschiedlich zwischen den beiden Plänen.
Schätzung des Beitrittsplans: 1
Schätzungen des Unterabfrageplans: 8.748
Die tatsächliche Anzahl der Zeilen, die aus dem Join herauskommen, beträgt 14.276.
Natürlich macht es absolut keinen intuitiven Sinn, dass die Join-Version abschätzen sollte, dass 3 Zeilen von location
einer einzelnen verknüpften Zeile stammen, während die Unterabfrage abschätzt, dass eine einzelne dieser Zeilen 8.748 aus derselben Verknüpfung erzeugt, aber ich war trotzdem in der Lage um dies zu reproduzieren.
Dies scheint zu passieren, wenn bei der Erstellung der Statistiken keine Überkreuzung zwischen den Histogrammen auftritt. Die Join-Version nimmt eine einzelne Zeile an. Und die einzelne Gleichheitssuche der Unterabfrage nimmt die gleichen geschätzten Zeilen an wie eine Gleichheitssuche für eine unbekannte Variable.
Die Kardinalität von Testläufen ist 26244
. Unter der Annahme, dass drei unterschiedliche Standort-IDs angegeben sind, schätzt die folgende Abfrage, dass 8,748
Zeilen zurückgegeben werden ( 26244/3
)
declare @i int
SELECT *
FROM testruns AS tr
WHERE tr.location_id = @i
Angesichts der Tatsache, dass die Tabelle locations
nur 3 Zeilen enthält, ist es einfach (wenn wir keine Fremdschlüssel annehmen), eine Situation zu konstruieren, in der die Statistiken erstellt und dann die Daten in einer Weise geändert werden, die sich dramatisch auf die tatsächliche Anzahl der zurückgegebenen Zeilen auswirkt, für die dies jedoch nicht ausreicht Lösen Sie die automatische Aktualisierung der Statistiken aus und kompilieren Sie den Schwellenwert neu.
Da SQL Server die Anzahl der Zeilen erhält, die aus diesem Join stammen, werden alle anderen Zeilenschätzungen im Join-Plan massiv unterschätzt. Die Abfrage bedeutet nicht nur, dass Sie einen seriellen Plan erhalten, sondern auch, dass die Speicherzuweisung nicht ausreicht, und dass die Sortierungen und Hash-Verknüpfungen mit verschüttet werden tempdb
.
Ein mögliches Szenario, das die tatsächlichen und geschätzten Zeilen in Ihrem Plan wiedergibt, ist unten aufgeführt.
CREATE TABLE location
(
id INT CONSTRAINT locationpk PRIMARY KEY,
location VARCHAR(MAX) /*From the separate filter think you are using max?*/
)
/*Temporary ids these will be updated later*/
INSERT INTO location
VALUES (101, 'Coventry'),
(102, 'Nottingham'),
(103, 'Derby')
CREATE TABLE testruns
(
location_id INT
)
CREATE CLUSTERED INDEX IX ON testruns(location_id)
/*Add in 26244 rows of data split over three ids*/
INSERT INTO testruns
SELECT TOP (5984) 1
FROM master..spt_values v1, master..spt_values v2
UNION ALL
SELECT TOP (5984) 2
FROM master..spt_values v1, master..spt_values v2
UNION ALL
SELECT TOP (14276) 3
FROM master..spt_values v1, master..spt_values v2
/*Create statistics. The location_id histograms don't intersect at all*/
UPDATE STATISTICS location(locationpk) WITH FULLSCAN;
UPDATE STATISTICS testruns(IX) WITH FULLSCAN;
/* UPDATE location.id. Three row update is below recompile threshold*/
UPDATE location
SET id = id - 100
Wenn Sie die folgenden Abfragen ausführen, erhalten Sie die gleiche geschätzte Abweichung von der tatsächlichen Abweichung
SELECT *
FROM testruns AS tr
WHERE tr.location_id = (SELECT id
FROM location
WHERE location = 'Derby')
SELECT *
FROM testruns AS tr
JOIN location loc
ON tr.location_id = loc.id
WHERE loc.location = ( 'Derby' )