Abfrageleistung


7

Warum

SELECT Barraportfolioname
FROM   portfolio
WHERE  id IN (SELECT DISTINCT i1.portfolioid
              FROM   Import i1
                     LEFT OUTER JOIN Import i2
                       ON i1.PortfolioID = i2.PortfolioID
                          AND i2.ImportSetID = 82
              WHERE  i1.ImportSetID = 83
                     AND i2.ID IS NULL)  

dauert 0 Sekunden, während die folgende Abfrage 5 Sekunden dauert.

SELECT DISTINCT p.BarraPortfolioName AS name
FROM   Import i1
       INNER JOIN Portfolio p
         ON p.ID = i1.PortfolioID
       LEFT OUTER JOIN Import i2
         ON i1.PortfolioID = i2.PortfolioID
            AND i2.ImportSetID = 82
WHERE  i1.ImportSetID = 83
       AND i2.ID IS NULL;  

Ich benutze SQL Server. Beide Tabellen haben Indizes für alle Spalten, die in der Abfrage verwendet werden, dh Portfolio-ID, ID, Import-ID.

Bearbeiten von gbn, basierend auf OP-Kommentar

Sie sagten:

Dies funktioniert viel besser als die beiden vorherigen Abfragen.

select
   BarraPortfolioName
from 
   (
   select distinct p.BarraPortfolioName,portfolioid
   from
        import i1
        inner join 
        portfolio p on p.id=i1.portfolioid
   where 
        importsetid = ?
   ) as p1
   left outer join
   (
   select distinct portfolioid 
   from import 
   where importsetid = ?
   ) as p2 on p1.portfolioid = p2.portfolioid
where 
   p2.portfolioid is null

6
Veröffentlichen Sie die Abfragepläne
Gaius

In der aktuellen Form ist diese Frage nicht zu beantworten (und wird sicherlich geschlossen, wenn Sie sie so belassen) - aber wenn es "schlechte Statistiken" gibt, die in den Plänen sichtbar sein sollten?
Jack sagt, versuchen Sie es mit topanswers.xyz

1
Aber sicherlich können gute Abfragetuner den Unterschied in den Abfragen eine Meile entfernt sehen ...
Rob Farley

Ich habe mir die Daten in meiner Tabelle angesehen und festgestellt, dass es viele bis viele Zuordnungen zwischen Portfolio-ID gibt, dh ein Importsatz hat dieselbe Portfolio-ID mehrmals. Daher habe ich meine Abfrage wie folgt umgeschrieben: "Wählen Sie BarraPortfolioName aus (wählen Sie ein bestimmtes p.BarraPortfolioName, Portfolio-ID aus dem Import von i1 Inner Join-Portfolio p auf p.id = i1.portfolioid, wobei importsetid =?) Als p1 links Outer Join aus (wählen Sie ein bestimmtes Portfolio aus) vom Import mit importsetid =?) als p2 auf p1.portfolioid = p2.portfolioid wobei p2.portfolioid null ist ". Dies funktioniert viel besser als die beiden vorherigen Abfragen.
TechExplorer

1
Wie können Sie null Sekunden mit null Sekunden mit der neu geschriebenen Abfrage vergleichen? Versuchen Sie es mit SET STATISTICS IO ON, um die Abfragen 1 und 3 zu vergleichen
gbn

Antworten:


9

Dies setzt voraus, dass beide die gleichen Ergebnisse liefern

  • Die erste ist eine "Semi-Verknüpfung" aufgrund der IN (Unterabfrage) (die DISTINCT wird nicht benötigt).
    Dies bedeutet, dass die Unterabfrage "kurzschließen" kann.

  • Die zweite ist eine äußere Verknüpfung und dann eine Einschränkung, gefolgt von einem DISTINCT-Aggregat.
    Dies sind 3 diskrete Hauptoperationen

Dieser "Kurzschluss" ist der Hauptgrund für den Unterschied, selbst bei der äußeren Verknüpfung in der Unterabfrage.

Für einfachere Abfragen würde die 2. Abfrage auf den gleichen Plan wie die 1. optimiert, da sie semantisch identisch ist. Je später die Version usw.

Weitere Informationen finden Sie hier (gleiche Logik, nur umgekehrt): Die Verwendung der NOT-Logik in Bezug auf Indizes

Und dies über "IN vs. JOIN vs. EXISTS" von SO-Benutzer Quassnoi auf seiner Website

Und ein ähnliches SO-Beispiel: https://stackoverflow.com/a/7221395/27535


4

Probieren Sie es aus mit:

SELECT
   (select p.BarraPortfolioName from Portfolio p where p.ID = i1.PortfolioID) AS name  
FROM Import i1  
WHERE i1.ImportSetID = 83 
group by i1.PortfolioID  
HAVING NOT EXISTS     
    (SELECT * FROM Import i2 
    WHERE i1.PortfolioID = i2.PortfolioID 
    AND i2.ImportSetID = 82);

Sie möchten lediglich die eindeutigen i1.PortfolioIDs suchen, diese Liste nach solchen filtern, die nicht in Importset 82 enthalten waren, und den Namen für diese IDs anzeigen.


In der Tat ist Ihre Abfrage sogar besser als die dritte Abfrage. Statistik für 3. Abfrage: Tabelle 'Import'. Scananzahl 375, logische Lesevorgänge 1222, physische Lesevorgänge 0, Tabelle 'Portfolio'. Scananzahl 0, logische Lesevorgänge 52140, physische Lesevorgänge 0 Statistik für Ihre Abfrage: Tabelle 'Portfolio'. Scananzahl 0, logische Lesevorgänge 3, physische Lesevorgänge 0, Tabelle 'Import'.
Scananzahl

Möglicherweise möchten Sie beim Import einen Index ixBlah erstellen (ImportSetID, PortfolioID) - falls Sie noch keinen haben.
Rob Farley

3

Wenn Sie keinen eindeutigen Index für BarraPortfolioName haben, müssen alle auf Duplikate überprüft werden. Dies ist in der ersten Abfrage nicht erforderlich, da Ihre IN-Klausel dies für Sie erledigt.

Versuchen Sie, einen eindeutigen Index (oder eine eindeutige Einschränkung) zu erstellen, und prüfen Sie, ob dies der Trick ist. Oder ändern Sie das zweite Skript, indem Sie das eindeutige Skript löschen und GROUP BY p.id, p.BarraPortfolioNameam Ende setzen. Dies sollte es ermöglichen, den Unterscheidungsprozess kurzzuschließen.


Sie verpassen den Punkt. Es geht darum, p.id in die Gruppierung aufzunehmen.
Rob Farley

Frühere Kommentare wurden entfernt, da ich sehe, was Sie mit dem GROUP BYJetzt meinen . Ich dachte, das würde die Semantik ändern, aber wenn sie BarraPortfolioNamenicht eindeutig ist, unterscheiden sich die beiden Abfragen im OP ohnehin semantisch, da die erste ebenfalls DISTINCThinzugefügt werden müsste . Beim Testen stelle ich immer noch fest, dass Abfrage 1 einen Semi-Join verwendet und Abfrage 2 jedoch nicht, sodass das OP nur bei 1 IMO bleiben sollte.
Martin Smith

Jep. Die from-Klausel sollte lauten:
Rob Farley

FROM Import i1 LEFT OUTER JOIN Import i2 ON i1.PortfolioID = i2.PortfolioID UND i2.ImportSetID = 82 INNER JOIN Portfolio p ON p.ID = i1.PortfolioID
Rob Farley

... und dies ist ein Problem mit der Qualitätssicherung, das von der Produktgruppe kaum anerkannt wird.
Rob Farley
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.