Warum macht diese WHERE-Klausel meine Abfrage 180 Mal langsamer?

9

Die folgende Abfrage wird in 1,6 Sekunden ausgeführt

%Vor%

Das Hinzufügen von AND shops.shop_id=86 zur letzten WHERE-Klausel bewirkt, dass die Abfrage in 292 Sekunden ausgeführt wird:

%Vor%

Ich hätte gedacht, dass die Begrenzung der Shop-Tabelle mit AND shops.shop_id=86 die Ausführungszeit reduzieren würde. Stattdessen hängt die Ausführungszeit von der Anzahl der Zeilen in der Produkttabelle ab, wobei products.shop_id der angegebenen shops.shop_id entspricht. In der Produkttabelle gibt es etwa 34.000 Zeilen mit products.shop_id = 86 und die Ausführungszeit beträgt 292 Sekunden. Für products.shop_id = 50 gibt es ungefähr 28.000 Zeilen und die Ausführungszeit beträgt 210 Sekunden. Für products.shop_id = 175 gibt es ungefähr 2K Zeilen und die Ausführungszeit beträgt 2,8 Sekunden. Was ist los?

EXPLAIN EXTENDED für die 1,6 Sekunden Abfrage ist:

%Vor%

SHOW WARNINGS für dieses EXPLAIN EXTENDED ist

%Vor%

EXPLAIN EXTENDED für die 292-Sekunden-Abfrage lautet:

%Vor%

SHOW WARNINGS für dieses EXPLAIN EXTENDED ist

%Vor%

Ich führe MySQL Client Version: 5.1.56. Die Shop-Tabelle hat einen primären Index für shop_id:

%Vor%

Ich habe den Ladentisch analysiert, aber das hat nicht geholfen.

Ich bemerke, dass wenn ich LEFT JOIN entferne, die Differenz in den Ausführungszeiten auf 0,12 Sekunden im Vergleich zu 0,28 Sekunden fällt.

Die Cez-Lösung, nämlich die 1,6-Sekunden-Version der Abfrage zu verwenden und irrelevante Ergebnisse durch Hinzufügen von rowed_results.shop_dummy=86 zur äußeren Abfrage (wie unten) zu entfernen, wird in 1,7 Sekunden ausgeführt. Dies umgeht das Problem, aber das Rätsel bleibt, warum 292-Sekunden-Abfrage ist so langsam.

%Vor%     
jela 15.11.2012, 20:30
quelle

3 Antworten

1

Nach dem Chat-Raum und dem Erstellen von Tabellen / Spalten, die der Abfrage entsprechen, habe ich die folgende Abfrage erstellt.

Ich habe meine innerste Abfrage gestartet, um auf der Tabelle für Sex, Produkt (für shop_id) und Favoriten zu sein. Da Sie dieses Produkt bei ShopA = Produkt ID = 1, aber das gleiche Produkt bei ShopB = Produkt ID = 2 (nur Beispiel) beschrieben haben, ist jedes Produkt IMMER einzigartig pro Shop und niemals dupliziert. Das heißt, ich kann das Produkt und shop_id MIT der Anzahl der Favoriten (falls vorhanden) bei dieser Abfrage, aber nur auf die Produkt-ID als Gruppe. Wie Shop-ID wird nicht ändern pro Produkt, das ich mit MAX (). Da du immer nach einem Datum von "gestern" und Geschlecht (Geschlecht = 0 weiblich) suchst, hätte ich die SEX-Tabelle indiziert (Datum, Geschlecht, Produkt_ID) ... Ich schätze, du fügst nicht jedes Mal 1000 von Gegenständen hinzu Tag ... Produkte haben offensichtlich einen Index für product_id (Primärschlüssel), und Favoriten sollten einen Index für product_id haben.

Von diesem Ergebnis (Alias ​​"sxFav") können wir dann einen direkten Join mit der Sex- und Produkttabelle durch diese "Product_ID" durchführen, um zusätzliche Informationen zu erhalten, wie Name des Shops, Datumsprodukt hinzugefügt, Produkt Beschreibung usw. Dieses Ergebnis wird dann von der shop_id, von der das Produkt verkauft wird, und vom Datum und schließlich von der Produkt-ID (aber Sie können überlegen, eine Beschreibungsspalte bei der inneren Abfrage zu erfassen und diese als Sortierung zu verwenden). Dies führt zum Alias ​​"PreQuery".

Da die Bestellung im Shop korrekt ist, können wir nun die @MySQLVariable-Referenzen hinzufügen, um jedem Produkt eine Zeilennummer zu geben, die der ursprünglichen Vorgehensweise ähnelt. Wird jedoch eine Shop-ID geändert, wird nur auf 1 zurückgesetzt.

%Vor%

Wenn Sie nun nach bestimmten "Paging" -Informationen suchen (z. B. 7 Einträge pro Shop), wickeln Sie die GESAMTE Abfrage oben in etwas wie ...

ein %Vor%

(oder zwischen 8 und 14, 15 und 21 usw. nach Bedarf) oder sogar

%Vor%     
DRapp 16.11.2012, 01:47
quelle
1

Sie sollten die shops.shop_id = 86 in die JOIN-Bedingung für Shops verschieben. Es gibt keinen Grund, es aus dem JOIN herauszuholen. Sie laufen Gefahr, dass MySQL zuerst JOINS und dann filtert. Ein JOIN kann den gleichen Job ausführen wie die a WHERE-Klausel, besonders wenn Sie nicht auf andere Tabellen verweisen.

%Vor%

Das Gleiche gilt für den Sex Join:

%Vor%

Abgeleitete Tabellen sind großartig, aber sie haben keine Indizes für sie. Normalerweise spielt dies keine Rolle, da sie normalerweise im RAM sind. Aber zwischen dem Filtern und dem Sortieren ohne Indizes können sich die Dinge summieren.

Beachten Sie, dass in der zweiten Abfrage, die viel länger dauert, die Tabellenverarbeitungsreihenfolge geändert wird. Die Shop-Tabelle befindet sich in der langsamen Abfrage oben, und die p1-Tabelle ruft 11799 Zeilen anstelle von 1 Zeile in der schnellen Abfrage ab. Es verwendet auch nicht mehr den Primärschlüssel. Das ist wahrscheinlich, wo dein Problem ist.

%Vor%     
Brent Baisley 16.11.2012 02:55
quelle
1

Gemessen an der Diskussion schneidet der Abfrageplaner schlecht ab, wenn er den Shop auf einer niedrigeren Ebene spezifiziert.

Fügen Sie der äußeren Abfrage rowed_results.shop_dummy=86 hinzu, um die gesuchten Ergebnisse zu erhalten.

    
Cez 16.11.2012 00:53
quelle

Tags und Links