2009-04-06 2 views
0

Ich habe etwas Ähnliches wie die folgenden:Was würde dazu führen, dass eine Abfrage bei Verwendung einer Unterabfrage langsam ausgeführt wird, aber nicht bei einer separaten Ausführung?

SELECT c.id 
FROM contact AS c 
WHERE c.id IN (SELECT s.contact_id 
    FROM sub_table AS s 
     LEFT JOIN contact_sub AS c2 ON (s.id = c2.sub_field) 
    WHERE c2.phone LIKE '535%') 
ORDER BY c.name 

Das Problem ist, dass die Abfrage eine sehr sehr sehr lange Zeit in Anspruch nimmt (> 2 Minuten), aber wenn ich die Unterabfrage nehmen, führen Sie es separat, implodieren die IDs und Fügen Sie sie in die Hauptabfrage ein, sie läuft in weniger als 1 Sekunde, einschließlich der Datenwiederherstellung und Implosion.

Ich habe überprüft, erklärt auf beiden Methoden und Schlüssel werden entsprechend und auf die gleiche Weise verwendet. Die Unterabfrage gibt nicht mehr als 200 IDs zurück.

Was könnte dazu führen, dass die Unterabfrage so lange dauert?

BTW, ich weiß, dass die obige Abfrage mit Joins geschrieben werden kann, aber die Abfrage, die ich habe, kann nicht sein - das ist nur eine vereinfachte Version.

Verwenden von MySQL 5.0.22.

+0

Können Sie vielleicht die genaue Version des von Ihnen verwendeten MySQL-Servers angeben? –

+0

Danke, jetzt kommen wir irgendwohin. Ich laufe 5.0.24 auf einem von mir, so nahe genug. Überprüfen einiger Testfälle, um zu sehen, ob der 6.0-Alpha-Bug dort auch vorhanden war. –

+0

... anscheinend nicht. Ungerade.Können Sie trotzdem die Beispielabfragen (und Problemumgehungen) in diesem Bugreport auf Ihre Anfragen überprüfen? Ihr Beispiel scheint fast identisch mit dem Bericht zu sein, auf dem der Optimierer krächzt. –

Antwort

0

Haben Sie den Ausführungsplan für die Abfrage überprüft? Dies wird Ihnen normalerweise das Problem zeigen.

+0

Wie finde ich das in MySQL? –

+0

EXPLAIN SELECT c.id ...; – Greg

+0

Ja, ich erwähnte das in der Frage. Es sieht so aus, als ob alles in Ordnung ist. –

0

Es ist eine korrelierte Unterabfrage. Es läuft einmal für jede Zeile im äußeren auswählen. (Ich denke. Sie haben zwei Tabellen mit dem gleichen Korrelationsnamen, ich nehme an, dass das ein Tippfehler ist. Dass Sie sagen, dass es nicht neu geschrieben werden kann, bedeutet, dass es korreliert ist.)

Ok, ich werde gebe dir etwas zum ausprobieren. Sie sagen, dass die Unterabfrage nicht korreliert ist und Sie immer noch nicht daran teilnehmen können. Und da Sie die Ausgabe der Unterabfrage verwenden und diese für die Unterabfrage lexikalisch ersetzen, wird die Hauptabfrage viel schneller ausgeführt.

Also versuchen Sie dies: Machen Sie die Unterabfrage in eine Ansicht: create view foo gefolgt von dem Text der Unterabfrage. Schreiben Sie dann die Hauptabfrage neu, um die "IN" -Klausel loszuwerden und stattdessen der Ansicht beizutreten.

Wie läuft das Timing?

+0

Ich habe das mit Absicht gemacht, aber ich habe es mit einem anderen Namen versucht (ich habe die Abfrage geändert) und es dauert genauso lange. –

+0

Ich würde sagen, die View-Option ist eine gute Idee, außer eine Ansicht für eine Abfrage zu erstellen, die einmal alle 2 Monate ausgeführt wird, ist möglicherweise nicht die beste. Das andere Problem mit Sichten in MySQL 5 ist, dass sie keine Indizes haben können ... also ist es nutzlos, sie zu suchen/ihnen beizutreten. –

+0

Sie verwenden jedoch die Indizes in den Basistabellen. Wenn Sie also davon ausgehen, dass diese ordnungsgemäß indiziert sind, ist das kein Problem. – tpdi

0

Können Sie nicht eine weitere Verknüpfung anstelle einer Unterabfrage ausführen?

SELECT c.id 
FROM contact AS c 
JOIN sub_table AS s on c.id = s.contact_id 
LEFT JOIN contact_sub AS cs ON (s.id = cs.sub_field) 
WHERE cs.phone LIKE '535%' 
ORDER BY c.name 
+0

Wie in der Frage erwähnt, ist dies ein Beispiel, nicht die eigentliche Abfrage und ja das Beispiel könnte als Join geschrieben werden. –

0

Da die Unterabfrage auf ein Feld bezieht sich sub_field im äußeren wählt, hat es für jede Zeile in der äußeren Tabelle einmal ausgeführt werden - die Ergebnisse für die innere Abfrage werden in der äußeren Tabelle mit jeder Zeile ändern .

+0

Ops, ich hätte den Outter- und Unterabfragetabellen verschiedene Aliase geben sollen. Mein Fehler. –

1

Was passiert, wenn Sie es so versuchen?

SELECT c.id 
FROM contact AS c 
INNER JOIN (SELECT s.contact_id 
    FROM sub_table AS s 
     LEFT JOIN contact_sub AS c2 ON (s.id = c2.sub_field) 
    WHERE c2.phone LIKE '535%') subq ON subq.contact_id=c.id 
ORDER BY c.name 

Angenommen, das Ergebnis von s.contact_id ist einzigartig. Sie können der Unterabfrage unterschiedliche hinzufügen, wenn dies nicht der Fall ist.

Ich verwende immer unkorrelierte Unterabfragen auf diese Weise, anstatt den Operator IN in der WHERE-Klausel zu verwenden.

Verwandte Themen