优化慢速SELECT查询

时间:2015-07-27 16:31:10

标签: mysql performance optimization

我在优化这个需要13s的查询时遇到了问题

SELECT `user_id`,`op`, COUNT(*) AS `count` FROM `imported_customer` 
WHERE (`id` IN (
      SELECT `imported_customer_id` FROM `history`
      WHERE `date` < NOW() - INTERVAL 10 DAY
      GROUP BY `imported_customer_id` 
      HAVING MAX(`event_type_id`)= 2
      )
) 
GROUP BY `op` 
ORDER BY `user_id`, `op`

说明:

id  select_type      table       type   possible_keys    key              key_len  ref rows Extra
1   PRIMARY imported_customer   index                    op                 35      1718    Using where; Using temporary; Using filesort
2   DEPENDENT SUBQUERY  history index                 imported_customer_id  8       2       Using where

子查询很好,它在38ms运行,并且运算符的结果列表是300个数字,这应该没问题。

所以唯一依赖的是count(*),在主查询中使用GROUP和ORDER。

解释该查询告诉&#34;使用where;使用临时;使用filesort&#34;,这是错误的优化查询的标志。

在表上,imported_customer是id,user_id和op。

的索引

但查询仍然很慢,如何优化呢?

SQLFiddle:http://sqlfiddle.com/#!9/02d37/2/0 - (查询中未使用的列未包括在内)由于数据量少而速度快但解释看起来相同

2 个答案:

答案 0 :(得分:1)

我认为你可以尝试在你的表imported_customer:

上添加这样的索引
INDEX `test2` (`user_id`,`op`)

然后使用

group by (`user_id`,`op`)

答案 1 :(得分:1)

您可以尝试将WHERE ... IN ()替换为JOIN,如此(http://sqlfiddle.com/#!9/3bb51/1/0):

   SELECT user_id,op, COUNT(*) AS count
     FROM imported_customer i 
     JOIN (
             SELECT imported_customer_id 
               FROM history
               WHERE `date` < NOW() - INTERVAL 10 DAY
            GROUP BY imported_customer_id 
              HAVING MAX(event_type_id)= 2
          ) h ON i.id = h.imported_customer_id
 GROUP BY user_id, op 
 ORDER BY user_id, op 

您应该考虑在历史记录表中使用覆盖索引(date, imported_customer_id, event_type_id)来帮助生成按日期过滤的聚合。

出于同样的原因,您应该考虑在导入的客户表上使用复合索引(id, user_id, op)

请注意,SQL Fiddle中的索引选择可能与扩展查询中的索引选择不同。

另请注意,您使用并可能滥用了GROUP BY的有害MySQL扩展。

不要被“使用临时;使用filesort”困惑。您在外部查询中执行的聚合计算类型需要这些操作。 Filesort并不总是意味着真实的文件;它可以指内存中间结果的排序。你是正确的,“使用where”并不是良好优化的标志。