繁体   English   中英

优化“ GROUP BY”查询,消除“在哪里使用”; 使用临时; 使用文件排序”

[英]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
  • 6G RAM,30M行

非常感谢你的帮助!

附言:第一次海报,对于任何违反最佳做法的行为,我们深表歉意。 我很高兴学习...

编辑:

答案之一表明

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM