2017-04-07 2 views
1

Ich habe drei Tabellen:SQL Server-Abfrage mit Unterabfragen - Leistungsprobleme

Tabelle 1: | dbo.pc_a21a22 |

batchNbr     Other columns... 
    --------     ---------------- 
     12345 
     12346 
     12347 

Tabelle 2: | dbo.outcome |

passageId     record 
    ----------    --------- 
     00003     200 
     00003      9 
     00004      7 

Tabelle 3: | dbo.passage |

passageId     passageTime  batchNbr 
    ----------    -------------  --------- 
     00001     2015.01.01   12345 
     00002     2016.01.01   12345 
     00003     2017.01.01   12345 
     00004     2018.01.01   12346 

Was ich tun mag: für jedes batchNbr in Tabelle 1 erhält zuerst seine neueste passageTime und die entsprechende passageID aus Tabelle 3. Mit diesem passageID, erhalten Sie die entsprechenden Zeilen in Tabelle 2 und festzustellen, ob eine dieser Reihen enthält den Datensatz 200. Pro PassageId gibt es höchstens 2 Datensätze in Tabelle 2

Was ist der effizienteste Weg, dies zu tun?

Ich habe bereits eine Abfrage erstellt, die funktioniert, aber es ist schrecklich langsam und daher für Tabellen mit Millionen von Zeilen ungeeignet. Irgendwelche Vorschläge, wie man die Abfrage ändert oder es anders macht? Das Ändern der Tabellenstruktur ist keine Option, ich habe nur Leserechte für die Datenbank.

Meine aktuelle Lösung (langsam):

SELECT TOP 50000 
    a.batchNbr, 
    CAST (CASE WHEN 200 in (SELECT TOP 2 record FROM dbo.outcome where passageId in (
    SELECT SubqueryResults.passageId From (SELECT Top 1 passageId FROM dbo.passage pass WHERE pass.batchNbr = a.batchNbr ORDER BY passageTime Desc) SubqueryResults 
    ) 
    ) then 1 else 0 end as bit) as KGT_IO_END 

    FROM dbo.pc_a21a22 a 

Die gewünschte Ausgabe ist:

batchNbr  200present 
--------- ---------- 
12345   1 
12346   0 

Antwort

3

Ich schlage vor, Sie Tabelle Beitritt verwenden, anstatt Unterabfragen.

select 
    a.*, b.* 
from 
    dbo.table1 a 
join 
    dbo.table2 b on a.id = b.id 
where 
    /*your where clause for filtering*/ 

EDIT:

Sie diese als Referenz verwenden könnte Join vs. sub-query

+1

Es hat eine sein 'select *'. - nicht 'wählen * .a' ..... aber ansonsten: perfekte Antwort! –

+0

Danke! Warum gibt es den drastischen Leistungsunterschied? – AlexGuevara

+0

@marc_s - Danke, mein Herr! Verpasste diesen einen. –

1

Versuchen Sie, diese

SELECT TOP 50000 a.*, (CASE WHEN b.record = 200 THEN 1 ELSE 0 END) AS 
KGT_IO_END 
FROM dbo.Test1 AS a 
LEFT OUTER JOIN 
(SELECT record, p.batchNbr 
FROM dbo.Test2 AS o 
LEFT OUTER JOIN (SELECT MAX(passageId) AS passageId, batchNbr FROM 
dbo.Test3 GROUP BY batchNbr) AS p ON o.passageId = p.passageId 
) AS b ON a.batchNbr = b.batchNbr; 

Die MAX Unterabfrage ist die neueste passageId von batchNbr zu bekommen. Allerdings wird Ihr Beispiel bekommt die Aufzeichnung nicht mehr als 200, da die passageId des Datensatz mit 200 00001, während die neuesten passageId der batchNbr 12345 00003.

verwende ich LEFT OUTER JOIN seit dem passageId von Table2 nicht mehr Spiel eine der neuesten passageId aus Tabelle3. Die resultierende Unterabfrage hätte keine Datensätze zu join zu Tabelle1. Daher würde INNER JOIN keine Datensätze aus Ihren Beispieldaten anzeigen.

Ausgabe von Ihrem Beispiel Daten:

batchNbr KGT_IO_END 
    12345   0 
    12346   0 
    12347   0 

Ausgang, wenn wir die passageId der Aufzeichnung 200-00003 (spätestens nach 12345) ändern

batchNbr KGT_IO_END 
    12345   1 
    12346   0 
    12347   0 
+0

danke für die Abfrage! Sie haben Recht mit dem PassageId-Problem. Ich habe es nicht gesehen, als ich mein Beispiel eingegeben habe - ich habe nur den ursprünglichen Post bearbeitet. Aber du hast meine Absicht bekommen :-) – AlexGuevara

+0

Also hat es für die echten Aufzeichnungen funktioniert? Lassen Sie es mich wissen, wenn Sie eine Anpassung benötigen. – CurseStacker

+0

Ich verstehe nicht vollständig, warum der Teil b.record = 200 in Ihrer ersten Zeile funktioniert, da es zwei Datensätze für diese PassageId gibt? Würde es nicht zwei Datensätze zurückgeben? – AlexGuevara