it-swarm.com.de

Was ist effizienter, eine where-Klausel oder ein Join mit mehr als einer Million Zeilentabellen?

Wir betreiben eine Website mit 250 MM Zeilen in einer Tabelle und in einer anderen Tabelle, der wir für die meisten Abfragen beitreten, mit knapp 15 MM Zeilen.

Beispielstrukturen:

MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows

Wir müssen regelmäßig einige Abfragen für alle diese Tabellen durchführen. Eine davon ist das Abrufen von Statistiken für kostenlose Benutzer (~ 10.000 kostenlose Benutzer).

Select Count(1) from DetailsTable dt 
join MasterTable mt on mt.Id = dt.MasterId 
join UserTable ut on ut.Id = mt.UserId 
where ut.Role is null and mt.created between @date1 and @date2

Das Problem ist, dass diese Abfrage manchmal eine verdammt lange Zeit dauert, da die Verknüpfungen lange vor dem Wo stattfinden.

In diesem Fall wäre es klüger, wherees anstelle von Joins oder möglicherweise where column in(...) zu verwenden?

20
Jeremy Boyd

Bei modernen RDBMS gibt es keinen Unterschied zwischen "expliziter JOIN" und "JOIN-in-the-WHERE" (wenn alle JOINS INNER sind) hinsichtlich Leistung und Abfrageplan.

Die explizite JOIN-Syntax ist klarer und weniger mehrdeutig (siehe Links unten).

Jetzt ist JOIN-before-WHERE eine logische Verarbeitung, keine tatsächliche Verarbeitung und die modernen Optimierer sind klug genug, dies zu realisieren.

Ihr Problem hier ist höchstwahrscheinlich die Indizierung.

Bitte zeigen Sie uns alle Indizes und Schlüssel in diesen Tabellen. Und die Abfragepläne

Hinweis: Diese Frage wäre bei StackOverflow sehr nahe gekommen, da es sich inzwischen um ein Duplikat handelt ... COUNT (1) vs COUNT (*) ist ebenfalls ein Mythos.

20
gbn

Sie müssen die Abfrage insgesamt umgestalten

Versuchen Sie, die WHERE-Klauseln früher und die JOINs später auszuführen

Select Count(1) from DetailsTable dt
join (Select UserId,Id FROM MasterTable where
created between @date1 and @date2) mt on mt.Id = dt.MasterId 
join (Select Id FROM UserTable WHERE Role is NULL) ut
on ut.Id = mt.UserId;

Selbst wenn Sie für diese überarbeitete Abfrage einen EXPLAIN-Plan ausführen und es schlechter aussieht als Ihr Original, versuchen Sie es trotzdem. Die intern erstellten temporären Tabellen führen kartesische Verknüpfungen durch, die Tabellen sind jedoch kleiner.

Ich habe diese Idee aus diesem YouTube-Video .

Ich habe die Prinzipien aus dem Video in einer sehr komplexen Frage in StackOverflow ausprobiert und eine Prämie von 200 Punkten erhalten.

@gbn erwähnte, dass Sie sicherstellen müssen, dass die richtigen Indizes vorhanden sind. In diesem Fall indizieren Sie bitte die erstellte Spalte in MasterTable.

Versuche es !!!

UPDATE 2011-06-24 22:31 EDT

Sie sollten diese Abfragen ausführen:

SELECT COUNT(1) AllRoles FROM UserTable;
SELECT COUNT(1) NullRoles FROM UserTable WHERE Role is NULL;

Wenn NullRoles X 20 <AllRoles (mit anderen Worten, wenn NullRoles weniger als 5% der Tabellenzeilen beträgt), sollten Sie einen nicht eindeutigen Index für die Rolle in UserTable erstellen. Andernfalls würde eine vollständige Tabelle mit UserTable ausreichen, da das Abfrageoptimierungsprogramm möglicherweise die Verwendung eines Index ausschließt.

UPDATE 2011-06-25 12:40 EDT

Da ich ein MySQL-DBA bin, muss ich dem MySQL-Abfrageoptimierer nicht durch positiven Pessimismus vertrauen und konservativ sein. Daher werde ich versuchen, eine Abfrage umzugestalten oder die erforderlichen Abdeckungsindizes zu erstellen, um den versteckten schlechten Gewohnheiten des MySQL Query Optimizer einen Schritt voraus zu sein. Die Antwort von @ gbn scheint vollständiger zu sein, da SQL Server möglicherweise mehr "Solidität" bei der Bewertung von Abfragen hat.

6
RolandoMySQLDBA

Wir hatten eine [Detail] -Tabelle mit ungefähr 75 Millionen Zeilen; Eine [Master] -Tabelle mit ca. 400 KB Zeilen und eine verwandte [Item] -Tabelle mit 7 Zeilen - immer und für immer. Es speicherte den kleinen Satz von „Artikelnummern“ (1-7) und modellierte ein Papierformular, von dem jeden Monat Millionen gedruckt und verteilt wurden. Die schnellste Abfrage war die, an die Sie am wenigsten zuerst denken würden, wenn Sie einen kartesischen Join verwenden. IIRC, es war so etwas wie:

SELECT m.order_id, i.line_nr, d.Item_amt
FROM Master m, Item i 
INNER JOIN Detail d ON m.order_id = d.order_id

Obwohl zwischen [Item] und [Detail] eine logische ID-Verknüpfung besteht, hat CROSS JOIN besser funktioniert als INNER JOIN.

Das RDBMS war Teradata mit seiner MPP-Technologie und IDR, was das Indexierungsschema war. Die 7-Zeilen-Tabelle hatte keinen Index, da TABLE SCAN immer die beste Leistung erbrachte.

1
Timothy Oleary