我正在使用此查询来获取{名称以小写字母开头的客户“a”}的所有员工:
SELECT * FROM employees
WHERE client_id IN (SELECT id FROM clients WHERE name LIKE 'a%')
列employees.client_id
是一个带INDEX client_id (index_id)
的int。子查询应该IMHO返回一个id-s列表,然后在WHERE子句中使用它。
当我EXPLAIN
查询时,主查询不使用索引(type:ALL
)。但当我EXPLAIN
从子查询中获取的列表(例如SELECT ... WHERE client_id IN (121,184,501)
),EXPLAIN
切换为type:range
,此查询的速度提高50%。
如何使查询使用子查询返回的数据的索引 - 或者,是否有更有效的方法来检索此数据? (将id-list检索到应用程序服务器,加入它并发送第二个查询在这里会更加昂贵。)
提前致谢。
答案 0 :(得分:12)
SELECT employees.*
FROM employees, clients
WHERE employees.client_id = clients.id
AND clients.name LIKE 'a%';
应该更快,因为优化者可以选择最有效的计划。在使用子查询编写它时,您强制它按特定顺序执行步骤,而不是让它选择最佳连接顺序。
作为一般规则,应避免使用子查询,因为它们通常不如连接查询高性能(尽管在某些情况下它们是不可避免的)
答案 1 :(得分:5)
您是否尝试使用JOIN
而不是子选择来执行此操作?
SELECT employees.* FROM employees, clients WHERE employees.client_id = clients.id AND clients.name LIKE 'a%';
答案 2 :(得分:4)
有关原因的具体说明
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。另外,这是bug report。
答案 3 :(得分:2)
值得指出的是,对于每个DBMS而言,连接性能优于子查询并不适用。但它确实适用于MySQL。
答案 4 :(得分:1)
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
答案 5 :(得分:0)
select * from X as _x where
exists(select * from Y as _y where _y.someField = _x.someField)
应该为你做的伎俩;)