为什么这个INNER JOIN / ORDER BY mysql查询这么慢?

时间:2015-02-08 03:14:52

标签: mysql performance indexing sql-order-by limit

我有非常大的客户数据库。在我添加ORDER BY之前,这个查询还可以。如何优化查询速度?

$sql = "SELECT * FROM customers 
LEFT JOIN ids ON customer_ids.customer_id = customers.customer_id AND ids.type = '10'
ORDER BY customers.name LIMIT 10";

ids.typecustomers.name是我的索引

解释查询

id  select_type  table      type    possible_keys   key     key_len     ref     rows    Extra   
1   SIMPLE       customers  ALL     NULL            NULL    NULL        NULL    955     Using temporary; Using filesort
1   SIMPLE       ids        ALL     type            NULL    NULL        NULL    3551    Using where; Using join buffer (Block Nested Loop)

2 个答案:

答案 0 :(得分:1)

(我假设您打算键入ids.customer_id = customer.customer_id而不是customer_ids.customer_id)

如果没有ORDER BY mysql抓住了10个类型10的前10个(索引),为他们查找客户,并完成了。 (注意,这里的LEFT JOIN实际上是一个INNER JOIN,因为连接条件只适用于两个表中都匹配的行)

使用ORDER BY mysql可能正在检索所有类型= 10个客户,然后按名字对它们进行排序以找到前10个。

您可以通过对customers表进行非规范化(将类型复制到客户记录中)或创建映射表来保存customer_id, name, type元组来加快速度。在任何一种情况下,都要在(type, name)上添加索引。如果使用映射表,请使用它与客户和ID进行3向连接。

如果type = 10相当常见,您还可以强制查询按名称遍历customers表,并使用STRAIGHT JOIN检查每个查询的类型。它不会像复合索引一样快,但它会比拉起所有匹配更快。

如上所述,在查询上运行EXPLAIN以查看mysql正在使用的查询计划。

答案 1 :(得分:0)

LEFT是问题所在。通过说LEFT JOIN,您暗示某些customers可能在ids中没有相应的行。并且您愿意接受字段的NULL来代替这样的ids行。

如果不是这样,那么删除LEFT。然后确保您的ids索引type启动。此外,customers必须有一个以PRIMARY KEY开头的索引(可能是customer_id)。有了这些,优化器可以从ids开始,在type之前进行过滤,从而减少工作量。

但是,它仍然必须在进行排序之前收集大量行(ORDER BY);只有这样才能传递10(LIMIT)。

当你在这里时,将INDEX(customer_id)添加到ids - 这就是对LEFT版本的杀戮性能。