MySQL按查询分组,多个总和不使用索引,滞后于使用文件排序

Posted

技术标签:

【中文标题】MySQL按查询分组,多个总和不使用索引,滞后于使用文件排序【英文标题】:MySQL group by query with multiple sums not using index, lagging on using filesort 【发布时间】:2015-10-09 18:54:27 【问题描述】:

鉴于下表...

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.html 和http://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)。它们都没有阻止使用临时表和文件排序。

【问题讨论】:

为 account_id 和 model 添加索引。顺序应该不相关。 这并没有消除文件排序。我试过 (account_id, model), (account_id, model, user_id), (account_id, model, user_id, value1, value2, value3, value4)。它们都没有阻止使用临时表和文件排序。 添加INDEX user_id (user_id) (account_id, model, user_id) 除非这些条件返回表格的很大一部分。您可以附加所有 valueX 列以使索引“覆盖”,但除非您的表真的很大,否则不需要这样做。 忽略临时/文件排序; 3 列索引运行得相当快吗? 【参考方案1】:

我的印象是,当所有列都在索引中时,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;

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

如果这不起作用,那么您的选择就更少了:

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

【讨论】:

以上是关于MySQL按查询分组,多个总和不使用索引,滞后于使用文件排序的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 where 和 Group by 返回多个总和结果

MySQL:与案例一起使用时按子句分组不使用索引

SQL中查询多个字段时,GROUP BY 要怎么使用?

按日期分组的 MySQL 累积总和

mysql 按表达式或函数分组多个字段分组排序

MySQL 查询随机滞后