MySQL - как использовать индекс в WHERE x IN (<subquery>) - PullRequest
8 голосов
/ 04 декабря 2008

Я использую этот запрос, чтобы получить всех сотрудников {клиентов с именем, начинающимся со строчной буквы "a"}:

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

Столбец employees.client_id - это int, с INDEX client_id (index_id). Подзапрос должен ИМХО возвращать список идентификаторов, который затем используется в предложении WHERE.

Когда я EXPLAIN запрос, основной запрос не использует индексы (type:ALL). Но когда я EXPLAIN список, взятый из подзапроса (например, SELECT ... WHERE client_id IN (121,184,501)), EXPLAIN переключается на type:range, и этот запрос выполняется быстрее на 50%.

Как я могу заставить запрос использовать индекс для данных, возвращаемых подзапросом, или есть более эффективный способ получения этих данных? (Получение списка идентификаторов на сервер приложений, присоединение к нему и отправка второго запроса здесь еще дороже).

Заранее спасибо.

Ответы [ 6 ]

12 голосов
/ 04 декабря 2008
SELECT employees.*
FROM   employees, clients
WHERE  employees.client_id = clients.id
AND    clients.name LIKE 'a%';

Должно быть быстрее, так как оптимизатор может выбрать наиболее эффективный план. При написании своего подзапроса, вы заставляете его выполнять шаги в определенном порядке, а не выбирать оптимальный порядок соединения.

Как правило, следует избегать подзапросов, так как они, как правило, будут менее производительными, чем запрос на соединение (хотя существуют определенные обстоятельства, когда они неизбежны)

5 голосов
/ 04 декабря 2008

Вы пытались сделать это с JOIN, а не с подпунктом?

SELECT employees.* FROM employees, clients WHERE employees.client_id = clients.id  AND clients.name LIKE 'a%';
4 голосов
/ 22 июля 2009

Для конкретного объяснения, почему

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

медленнее, чем

SELECT * FROM employees WHERE client_id IN (1,2,3,4)

Ознакомьтесь с этой частью руководства по MySQL, в частности с третьей точкой: http://dev.mysql.com/doc/refman/5.0/en/subquery-restrictions.html. Также этот отчет об ошибке .

2 голосов
/ 04 декабря 2008

Стоит отметить, что объединения, работающие лучше, чем подзапросы, не выполняются для каждой существующей СУБД. Это, конечно, для MySQL.

1 голос
/ 04 декабря 2008
SELECT e.*  
FROM employees e  
WHERE EXISTS (   
  SELECT 1    
  FROM clients c  
  WHERE c.id = e.client_id   
  AND c.name LIKE 'a%'
)

Вы можете переписать запрос, используя EXISTS . В MySQL это определенно дает улучшение производительности. Для получения дополнительной справки по оптимизации вы можете обратиться: MySQL-In-Query-Optimization

0 голосов
/ 04 декабря 2008
select * from X as _x where 
  exists(select * from Y as _y where _y.someField = _x.someField)

Должен сделать трюк для вас;)

...