none
Unterschied zw. JOIN- und WHERE-Klausel für die Abfrageleistung RRS feed

  • Frage

  • Hi,

    ich habe folgende Abfrage:

    SELECT
    	<Feldliste>
    FROM tabelle t1
    LEFT OUTER JOIN tabelle t2
    	ON t2.ID = t1.Parent_ID
    	AND t2.Datum >= '20190101'
    	AND t2.Datum < '20200101'

    Diese Abfrage wurde abhängig von den Daten jetzt irgendwie zu langsam. Ich habe zunächst INDEX REBUILD ALL gemacht. Die Tabelle hat einen gruppierten Primary-Key auf der ID-Spalte und einen nicht gruppierten Index auf der Parent_ID-Spalte. Sonst keine Indizes. Nun habe ich versucht über weitere Indizierungen der Spalten ID, Parent_ID und Datum und Kombinationen davon die Abfragegeschwindigkeit zu verbessern. Das hat nicht besonders gut funktioniert. Am Ende habe ich das Datums-Kriterium aus dem LEFT OUTER JOIN in die WHERE-Klausel genommen, wie hier zu sehen:

    SELECT
    	<Feldliste>
    FROM tabelle t1
    LEFT OUTER JOIN tabelle t2
    	ON t2.ID = t1.Parent_ID
    WHERE t2.ID IS NULL
    	OR
    	(
    		t2.Datum >= '20190101'
    		AND t2.Datum < '20200101'
    	)
    

    Das hat zu einer extreme Verbesserung geführt. Warum ist das so? Kann mir das bitte jemand erklären?

    Vielen Dank schon mal.

    Franz


    Donnerstag, 14. November 2019 11:46

Antworten

  • Weil es augenscheinlich nicht das Gleiche ist. Der Unterschied liegt wohl an dem Zeitpunkt, wann das. JOIN ausgeführt wird Und damit wann welche und wieviele Daten verarbeitet werden.

    Vielleicht hilft dir das hier weiter:

    https://stackoverflow.com/questions/354070/sql-join-where-clause-vs-on-clause



    Donnerstag, 14. November 2019 12:05
  • Da hat Eiko recht. Du siehst es z. B. im Ausführungsplan, dass bei der zweiten Variante wahrscheinlich ein Filter am Ende auftaucht, der das bis dahin fertig gestellte Resultset beschneidet. Hier ein kleines Beispiel, um die Unterschiede zu verdeutlichen. Einmal kommen 5 Zeilen, beim zweiten Mal nur 4 Zeilen (wegen des nachgelagerten Filters) heraus.

    use tempdb
    go
    
    create table #tabelle (Parent_ID int, ID int not null, Datum date not null);
    ALTER TABLE #tabelle add Constraint XPKTabelle Primary Key (ID);
    Create Index xie1tabelle on #tabelle (Parent_ID);
    
    Insert into #tabelle(Parent_ID, ID, Datum) values 
    (NULL, 1, '2019-01-01'),
    (1, 2, '2019-01-02'),
    (1, 3, '2019-01-03'),
    (2, 4, '2018-01-02'),
    (4, 5, '2017-01-02');
    
    
    SELECT
    	*
    FROM #tabelle t1
    LEFT OUTER JOIN #tabelle t2
    	ON t2.ID = t1.Parent_ID
    	AND t2.Datum >= '20190101'
    	AND t2.Datum < '20200101'
    
    go
    
    
    SELECT
    	*
    FROM #tabelle t1
    LEFT OUTER JOIN #tabelle t2
    	ON t2.ID = t1.Parent_ID
    WHERE t2.ID IS NULL
    	OR
    	(
    		t2.Datum >= '20190101'
    		AND t2.Datum < '20200101'
    	);
    
    
    Drop Table #tabelle;
    go


    Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu

    Donnerstag, 14. November 2019 12:35

Alle Antworten

  • Weil es augenscheinlich nicht das Gleiche ist. Der Unterschied liegt wohl an dem Zeitpunkt, wann das. JOIN ausgeführt wird Und damit wann welche und wieviele Daten verarbeitet werden.

    Vielleicht hilft dir das hier weiter:

    https://stackoverflow.com/questions/354070/sql-join-where-clause-vs-on-clause



    Donnerstag, 14. November 2019 12:05
  • Da hat Eiko recht. Du siehst es z. B. im Ausführungsplan, dass bei der zweiten Variante wahrscheinlich ein Filter am Ende auftaucht, der das bis dahin fertig gestellte Resultset beschneidet. Hier ein kleines Beispiel, um die Unterschiede zu verdeutlichen. Einmal kommen 5 Zeilen, beim zweiten Mal nur 4 Zeilen (wegen des nachgelagerten Filters) heraus.

    use tempdb
    go
    
    create table #tabelle (Parent_ID int, ID int not null, Datum date not null);
    ALTER TABLE #tabelle add Constraint XPKTabelle Primary Key (ID);
    Create Index xie1tabelle on #tabelle (Parent_ID);
    
    Insert into #tabelle(Parent_ID, ID, Datum) values 
    (NULL, 1, '2019-01-01'),
    (1, 2, '2019-01-02'),
    (1, 3, '2019-01-03'),
    (2, 4, '2018-01-02'),
    (4, 5, '2017-01-02');
    
    
    SELECT
    	*
    FROM #tabelle t1
    LEFT OUTER JOIN #tabelle t2
    	ON t2.ID = t1.Parent_ID
    	AND t2.Datum >= '20190101'
    	AND t2.Datum < '20200101'
    
    go
    
    
    SELECT
    	*
    FROM #tabelle t1
    LEFT OUTER JOIN #tabelle t2
    	ON t2.ID = t1.Parent_ID
    WHERE t2.ID IS NULL
    	OR
    	(
    		t2.Datum >= '20190101'
    		AND t2.Datum < '20200101'
    	);
    
    
    Drop Table #tabelle;
    go


    Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu

    Donnerstag, 14. November 2019 12:35