2008-12-04 2 views
8

ich diese Abfrage mit allen Mitarbeitern der {Kunden mit Namen mit Klein Start "a"} erhalten:MySQL - wie Index verwendet in WHERE x IN (<subquery>)

SELECT * FROM employees 
    WHERE client_id IN (SELECT id FROM clients WHERE name LIKE 'a%') 

Spalte employees.client_id eine ist int, mit INDEX client_id (index_id). Die Unterabfrage sollte IMHO eine Liste von ID-s zurückgeben, die dann in der WHERE-Klausel verwendet wird.

Bei der Abfrage EXPLAIN verwendet die primäre Abfrage keine Indizes (type:ALL). Aber wenn ich EXPLAIN eine Liste aus der Unterabfrage (z. B. SELECT ... WHERE client_id IN (121,184,501)), die EXPLAIN wechselt zu type:range, und diese Abfrage wird um 50% schneller.

Wie kann ich sicherstellen, dass die Abfrage den Index für die von der Unterabfrage zurückgegebenen Daten verwendet - oder gibt es eine effizientere Methode zum Abrufen dieser Daten? (Das Abrufen der ID-Liste zum Anwendungsserver, das Verbinden und Senden einer zweiten Abfrage ist hier noch teurer).

Vielen Dank im Voraus.

Antwort

12
SELECT employees.* 
FROM employees, clients 
WHERE employees.client_id = clients.id 
AND clients.name LIKE 'a%'; 

Sollte schneller sein, da der Optimierer den effizientesten Plan wählen kann. Wenn Sie es mit einer Unterabfrage schreiben, zwingen Sie es dazu, die Schritte in einer bestimmten Reihenfolge auszuführen, anstatt die optimale Verknüpfungsreihenfolge wählen zu lassen.

Als allgemeine Regel Unterabfragen sollten vermieden werden, da sie in der Regel weniger performant sein werden als eine Join-Abfrage (obwohl bestimmte Umstände dort sind, wo sie unvermeidlich sind)

+0

Konnte auch INNER JOIN-Syntax verwenden. – MarkR

+0

Ich habe Fälle gesehen, in denen der Abfrageoptimierer wirklich falsch ist, und eine Unterabfrage zur Rückgabe von IDs wurde schneller geladen. Aber es war ein wirklich spezifischer Fall. Siehe: http://www.benlumley.co.uk/2008/06/25/mysql-query-optimizer-left-lacking/ wenn Sie an Details interessiert sind. – benlumley

5

Haben Sie dies mit einem JOIN zu tun versucht, und kein Subselect?

2

Es ist erwähnenswert, dass Joins, die besser als Unterabfragen funktionieren, nicht für jedes DBMS gelten, das es gibt. Es ist sicher für MySQL.

0
select * from X as _x where 
    exists(select * from Y as _y where _y.someField = _x.someField) 

Sollte der Trick für Sie;)

1
SELECT e.* 
FROM employees e 
WHERE EXISTS ( 
    SELECT 1  
    FROM clients c 
    WHERE c.id = e.client_id 
    AND c.name LIKE 'a%' 
) 

Sie können die Abfrage umschreiben mit VORHANDEN. In MySQL gibt es definitiv eine Leistungsverbesserung. Für weitere Hilfe bei der Optimierung können Sie verweisen: MySQL-In-Query-Optimization

+0

Ich glaube nicht, dass die Verwendung von Unterabfragen eine Verbesserung mit MySQL darstellt. – mat

Verwandte Themen