MySQL没有使用SUM中的索引和GROUP BY查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL没有使用SUM中的索引和GROUP BY查询相关的知识,希望对你有一定的参考价值。

我刚刚创建了一个表:

CREATE TABLE `table_test` (
`time` date NOT NULL,
`line_id` char(36) NOT NULL,
`location_id` char(36) NOT NULL,
`placement_id` char(36) NOT NULL,
`flight_id` char(36) NOT NULL,
`impressions` int(11) DEFAULT `0`,
PRIMARY KEY (`time`,`line_id`,`location_id`,`placement_id`,`flight_id`),
KEY `table_test_IDX` (`time`,`placement_id`,`line_id`,`impressions`) USING 
BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

然后当我尝试执行查询时:

SELECT 
  time,
  placement_id,
  line_id,
  SUM(impressions) AS totalImpress
FROM
  table_test
WHERE
  time BETWEEN '2017-11-01' AND '2017-11-30'
GROUP BY time , placement_id , line_id;

它总是使用Using where; Using temporary; Using filesort,在这种情况下,我希望查询使用table_test_IDX

我在这做错了什么?

多谢。

答案

如果您仔细阅读mysql documentation以优化聚合查询,您会发现有两种方法可以优化GROUP BY查询,即松散和紧密的索引扫描。但是,对于这些扫描中的任何一个,一个警告是选择列表中使用的唯一聚合函数是MINMAX。因为您选择的是SUM,所以这些优化不可用。

使用可以使WHERE子句受益的索引是有意义的,因为这可能让我们在查询计划的早期就从结果集中丢弃记录。但是,为了计算每个组的总和,MySQL必须触摸剩余表中的每个记录。为了获得总和,没有办法解决这个问题,所以我们如何访问所有这些记录并不重要。

另一答案

我猜你正在使用UUID?将CHAR(36)改为CHAR(36) CHARACTER SET ascii。更好的是将它们打包成“BINARY”(16)。 (参见http://mysql.rjweb.org/doc.php/uuid。)这将尺寸从108缩小到36到16。

你说它正在使用filesort等,但它是否使用PRIMARY?请提供EXPLAIN SELECT ...

但是,为了更快地加速,请考虑构建和维护“汇总表”。 (参见http://mysql.rjweb.org/doc.php/summarytables。)如果每个组合(time,placement_id,line_id)在摘要表中有一行,则可以删除GROUP BYSUM。 (如果按小时总结,你仍然需要那些。)

以上是关于MySQL没有使用SUM中的索引和GROUP BY查询的主要内容,如果未能解决你的问题,请参考以下文章

使用 sum 和 group by 选项的 Mysql 查询运行速度非常慢

使用 MySQL 通过 JOIN 获取 GROUP BY 中的 SUM

MySQL 条件 SUM 使用 GROUP BY 和 DISTINCT

将包含 where、group by、sum 和必须的 MySQL 语句转换为 Linq to Sql

使用函数 SUM() 和 Group by 将 Mysql 查询转换为 SQL 查询

记一次MySQL Group by 的坑