簡體   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