我有一个简单的查询,没有连接,运行速度很慢(20秒+)。查询的表有大约400k行,并且where子句中使用的所有列都被编入索引。
SELECT deals.id, deals.title,
deals.amount_sold * deals.sale_price AS total_sold_total
FROM deals
WHERE deals.country_id = 33
AND deals.target_approved = 1
AND deals.target_active = 1
AND deals.finished_at >= '2012-04-01'
AND deals.started_at <= '2012-04-30'
ORDER BY total_sold_total DESC
LIMIT 0, 10
我上周以来一直在努力解决这个问题,请我帮忙:)
更新1
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE deals index_merge NewIndex3,finished_at_index,index_deals_on_country_id,index_deals_on_target_active,index_deals_on_target_approved index_deals_on_target_active,index_deals_on_target_approved,index_deals_on_country_id 2,2,5 \N 32382 Using intersect(index_deals_on_target_active,index_deals_on_target_approved,index_deals_on_country_id); Using where; Using filesort
答案 0 :(得分:3)
要改进选择,请按照指定的顺序使用WHERE子句中的列创建以下复合索引:
(country_id, target_approved, target_active, finished_at)
(country_id, target_approved, target_active, started_at)
首先需要具有更高基数的列,其中范围最后。 MySQL不能utilize any key parts past the first range,这就是为什么我们有两个单独的索引在WHERE子句(>=
和<=
)范围内分歧。
如果MySQL没有通过索引合并使用这两个索引,那么您可以考虑删除其中一个索引。
不幸的是,在订购行之前,MySQL仍然必须返回所有行,计算total_sold_total。换句话说,MySQL必须在检索完整个数据集后手动对行进行排序。
排序所需的时间与结果集的大小成正比。
无法使用LIMIT优化,因为在排序后应用了LIMIT。
不幸的是,在WHERE子句中使用范围会阻止您将预先计算的total_sold_total列添加到索引的末尾,以便按顺序返回结果,这将阻止手动排序。