[英]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.