2

我有一个没有连接的简单查询,运行速度非常慢(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
4

1 回答 1

3

要改进选择,请使用 WHERE 子句中的列按指定顺序创建以下复合索引:

(country_id, target_approved, target_active, finished_at)
(country_id, target_approved, target_active, started_at)

您首先需要具有较高基数的列,最后是范围。MySQL 不能利用第一个范围之外的任何关键部分,这就是为什么我们有两个独立的索引,它们在 WHERE 子句 (>=<=) 的范围内发散。

如果 MySQL 没有通过索引合并使用这两个索引,那么您可能会考虑删除其中一个。

不幸的是,MySQL 仍然必须返回所有行,计算 total_sold_total,然后才能对行进行排序。换句话说,MySQL 必须在检索到整个数据集后手动对行进行排序。

排序所需的时间将与结果集的大小成正比。

不能使用 LIMIT 优化,因为 LIMIT 是在排序之后应用的。

不幸的是,在 WHERE 子句中有范围会阻止您将预先计算的 total_sold_total 列添加到索引的末尾以按顺序返回结果,这将阻止手动排序。

于 2012-06-01T18:38:46.473 回答