我有非常大的客户数据库。在我添加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.type
和customers.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)
答案 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版本的杀戮性能。