Wir betreiben eine Website mit 250-mm-Zeilen in einer Tabelle und in einer anderen Tabelle, mit der wir sie für die meisten Abfragen verknüpfen, 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
Für all diese Tabellen müssen wir regelmäßig einige Abfragen durchführen. Eine davon ist das Sammeln von Statistiken für freie Benutzer (~ 10.000 freie 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 verdammt lange dauert, da die Verknüpfungen lange vor dem Wo stattfinden.
Wäre es in diesem Fall sinnvoller, wheres anstelle von Joins zu verwenden oder möglicherweise where column in(...)
?
join
best-practices
Jeremy Boyd
quelle
quelle
Antworten:
Bei modernen RDBMS gibt es hinsichtlich der Leistung und des Abfrageplans keinen Unterschied zwischen "Explicit JOIN" und "JOIN-in-the-WHERE" (wenn alle JOINS INNER sind).
Die explizite JOIN-Syntax ist klarer und weniger mehrdeutig (siehe Links unten).
Jetzt ist das 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 in der Nähe gewesen, da es sich inzwischen um ein Duplikat handelt ... COUNT (1) vs COUNT (*) ist ebenfalls ein kaputter Mythos.
quelle
join
und gibtwhere
. Ich optimiere ständig die Abfragen mit langer Laufzeit und manchmal sind die Abfragen mit der using-where
Klausel um denjoin
Faktor bis zum 70-fachen leistungsfähiger als die Abfragen mit der using- Klausel . Wenn es so einfach und unkompliziert wäre, wäre das Leben alles Regenbogen und Einhörner. Und hier geht es nicht um eine uralte undurchsichtige Engine - im Moment schaue ich auf den 70-fachen Vorteil derwhere
Klausel in SQL 2012.where
Klauselabfrage innerhalb des großen Stapels ausgeführt wird, in dem sie enthalten sein soll, übertrifft sie diejoin
Abfrage um ein Vielfaches. Die SQL-Abfragen werden nicht im luftleeren Raum ausgeführt - sie werden vom Rest der Servernutzlast beeinflusst, und häufigwhere
schneiden die Klauselabfragen recht gut ab, was ärgerlich ist, da diejoin
Syntax in der Tat viel sauberer ist.Sie müssen die Abfrage insgesamt umgestalten
Versuchen Sie, die WHERE-Klauseln früher und die JOINs später auszuführen
Selbst wenn Sie einen EXPLAIN-Plan für diese überarbeitete Abfrage 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, mit denen gearbeitet werden soll, sind jedoch kleiner.
Ich habe diese Idee aus diesem YouTube-Video .
Ich habe die Prinzipien des Videos in einer sehr komplexen Frage in StackOverflow ausprobiert und bekam 200 Punkte Kopfgeld.
@gbn erwähnte, dass sichergestellt werden muss, 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:
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 Indexes ausschließt.
UPDATE 2011-06-25 12:40 EDT
Da ich ein MySQL-DBA bin, erfordert meine Methode, dem MySQL-Abfrageoptimierer durch positiven Pessimismus nicht zu vertrauen und konservativ zu sein. Daher werde ich versuchen, eine Abfrage umzugestalten oder die erforderlichen Abdeckungsindizes zu erstellen, um die verborgenen schlechten Gewohnheiten des MySQL Query Optimizer zu überwinden. Die Antwort von @ gbn scheint vollständiger zu sein, da SQL Server bei der Bewertung von Abfragen möglicherweise mehr "Verstandeskraft" besitzt.
quelle
Wir hatten eine [Detail] -Tabelle mit etwa 75 Millionen Zeilen; Eine [Master] -Tabelle mit ca. 400 KB Zeilen und eine zugehörige [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 wahrscheinlich zuerst gedacht haben, und zwar unter Verwendung eines kartesischen Joins. IIRC, es war so etwas wie:
Obwohl es eine logische Verknüpfung zwischen [Item] und [Detail] gibt, hat CROSS JOIN besser funktioniert als INNER JOIN.
Das RDBMS war Teradata mit seiner MPP-Technologie und IDR, wie das Indexierungsschema lautete. Die 7-Zeilen-Tabelle hatte keinen Index, da TABLE SCAN immer die beste Leistung erbrachte.
quelle