[英]Optimization of 'GROUP BY'-Query, eliminate 'Using where; Using temporary; Using filesort'
我遇到了一个我似乎无法解决的MySQL问题。 为了能够快速执行GROUP BY
查询以进行报告,我已经将几张表格非规范化为以下表格(该表格由其他表格上的触发器维护,对此我表示放心):
DROP TABLE IF EXISTS stats;
CREATE TABLE stats (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datetime` datetime NOT NULL,
`datetime_hour` datetime NOT NULL,
`datetime_day` datetime NOT NULL,
`step_id` int(11) NOT NULL,
`check_id` int(11) NOT NULL,
`probe_id` int(11) NOT NULL,
`execution_step_id` int(11) NOT NULL,
`value_of_interest` int(11) DEFAULT NULL,
`internal` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `index_stats_on_execution_step_id` (`execution_step_id`),
CONSTRAINT `stats_step_id_fk` FOREIGN KEY (`step_id`) REFERENCES `steps` (`id`) ON DELETE CASCADE,
CONSTRAINT `stats_check_id_fk` FOREIGN KEY (`check_id`) REFERENCES `checks` (`id`) ON DELETE CASCADE,
CONSTRAINT `stats_probe_id_fk` FOREIGN KEY (`probe_id`) REFERENCES `probes` (`id`) ON DELETE CASCADE,
CONSTRAINT `stats_execution_step_id_fk` FOREIGN KEY (`execution_step_id`) REFERENCES `execution_steps` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
不管我在表上放什么索引,下面的查询仍将在“ Using where; Using temporary; Using filesort
一文中作一解释Using where; Using temporary; Using filesort
Using where; Using temporary; Using filesort
Using where; Using temporary; Using filesort
或它们的任意组合(所有这些都会导致查询以无法接受的性能运行):
SELECT
datetime_day,
step_id,
CAST(AVG(value_of_interest) AS UNSIGNED) AS value_of_interest
FROM
stats
WHERE
check_id = 78
AND probe_id = 1
AND (datetime_day >= '2014-03-28 15:58:00' AND datetime_day <= '2014-10-28 15:58:00')
AND (internal = 0)
GROUP BY
datetime_day, step_id
ORDER BY
datetime_day, step_id
我需要在表定义中设置哪些索引和/或需要如何修改查询以使其以合理的查询执行计划执行?
环境规格:
Fedora release 19 (Schrödinger's Cat)
mysql Ver 15.1 Distrib 5.5.34-MariaDB, for Linux (x86_64) using readline 5.1
非常感谢你的帮助!
附言:第一次海报,对于任何违反最佳做法的行为,我们深表歉意。 我很高兴学习...
编辑:
答案之一表明
ALTER TABLE `stats` ADD INDEX newindex (check_id, probe_id, internal, datetime_day, step_id);
情况有所改善。 我之前已经尝试过该索引,并得到以下结果:
+------+-------------+---------------------------+-------+---------------+----------+---------+------+--------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------------------------+-------+---------------+----------+---------+------+--------+------------------------------------+
| 1 | SIMPLE | stats | range | newindex | newindex | 17 | NULL | 605682 | Using index condition; Using where |
+------+-------------+---------------------------+-------+---------------+----------+---------+------+--------+------------------------------------+
但是,是否不应该有一种方法可以通过链接中提到的“松/紧索引扫描”来执行查询? 不过,我似乎无法使其正常工作,而且我不确定我是否正确理解了上述文章。
您有60万行要扫描,因此无法立即运行。
为什么您需要CAST(AVG(value_of_interest) AS UNSIGNED)
? 是否可以避免,也许可以通过在插入之前清除数据来避免?
该索引将使其成为“使用索引”,这将使其变得更快。 但是,如果这不是您唯一的查询,那么添加它似乎很愚蠢。
INDEX newindex (check_id, probe_id, internal, datetime_day, step_id, value_of_interest)
有奇怪的开始/结束时间吗? (十五时58分00秒)
汇总数据仓库表的“实际”解决方案是构建和维护“汇总表”。 对于有问题的查询,这样的表将具有check_id,probe_id,内部,step_id,datetime_hour,SUM(value_of_interest),COUNT(*)。 前5个是主键。 您应该每小时在表中添加另一行。 该报告(数小时,数天,数周,数月)将通过执行SUM(总和)/ SUM(计数)来获得AVG。
在我的摘要表博客中有更多讨论。
众所周知,order by子句会导致查询性能降低。 话虽这么说,拥有更好的索引来更好地匹配您的条件和分组子句将有所帮助。
我建议一个复合索引(在多个字段上)为
(check_id,probe_id,内部,datetime_day,step_id)
这样,将优化您的WHERE子句,然后最后两列都与group / order子句匹配以对其进行优化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.