MySQL分组查询,多个总和不使用索引,滞后于使用filesort

时间:2015-10-09 18:54:28

标签: mysql group-by database-performance database-optimization filesort

鉴于下表......

CREATE TABLE values_table (
  id int(11) NOT NULL auto_increment,
  account_id int(11) NOT NULL,
  user_id int(11) NOT NULL,
  model varchar(255) NOT NULL,
  ...
  value1 int(11) NOT NULL default '0',
  value2 int(11) NOT NULL default '0',
  value3 int(11) NOT NULL default '0',
  value4 int(11) NOT NULL default '0',
  PRIMARY KEY  (id),
  ....
) ENGINE=InnoDB AUTO_INCREMENT=2364641 DEFAULT CHARSET=utf8;

以及以下查询...

SELECT user_id, SUM(value1) AS value1, SUM(value2) AS value2, SUM(value3) AS value3, SUM(value4) as value4
from values_table
where account_id = 10 and model = 'ModelName'
group by user_id;

....应该将哪些字段添加到索引中以及确保执行不会以Using temporary; Using filesort;结束的顺序?

我尝试调整http://mysqldba.blogspot.com/2008/06/how-to-pick-indexes-for-order-by-and.htmlhttp://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html中描述的详细信息,但没有运气。

更新 我已尝试(account_id, model)(account_id, model, user_id)(account_id, model, user_id, value1, value2, value3, value4)。它们都不会阻止使用临时表和filesort。

1 个答案:

答案 0 :(得分:0)

我的印象是当所有列都在索引中时,MySQL只能用索引优化group by。然后,只能优化这些查询的子集。您的问题已经指向文档,但这里是最新的version

您可以使用(account_id, model)上的索引减少数据量。但是,您可能仍然有很多匹配,然后MySQL对索引和group by非常挑剔。

有一种方法可以让MySQL使用索引进行聚合。如果您只有一个计算列,那么您可以尝试:

select u.user_id,
       (select sum(v.value1)
        from values_table v
        where v.account_id = 10 and v.model = 'ModelName' and
              v.user_id = u.user_id
       ) as sum1
from (select distinct user_id
      from values_table
      where v.account_id = 10 and v.model = 'ModelName'
     ) u
group by u.user_id;

这应该使用values_table(account_id, model, user_id)上的索引作为from中的子查询。它还应该使用相关子查询的索引:values_table(user_id, account_id, model, value1)是理想的。但是,您必须为输出中的每个列重复此构造(可能还有最佳索引)。如果你有十个,那么一个聚合列的速度会更快。

如果这不起作用,那么您可以选择更少的选项:

  • 确定您确实需要一个限制性更强的where子句来减少数据量。
  • 使用触发器维护用户级别的预聚合数据。