【发布时间】:2011-03-09 20:31:54
【问题描述】:
什么是在 MySQL 中获取累积和的“正确”查询?
我有一个表格,我在其中保存有关文件的信息,一列列表包含文件的大小(以字节为单位)。 (实际文件保存在磁盘上的某个地方)
我想得到这样的累积文件大小:
+------------+---------+--------+----------------+
| fileInfoId | groupId | size | cumulativeSize |
+------------+---------+--------+----------------+
| 1 | 1 | 522120 | 522120 |
| 2 | 2 | 316042 | 316042 |
| 4 | 2 | 711084 | 1027126 |
| 5 | 2 | 697002 | 1724128 |
| 6 | 2 | 663425 | 2387553 |
| 7 | 2 | 739553 | 3127106 |
| 8 | 2 | 700938 | 3828044 |
| 9 | 2 | 695614 | 4523658 |
| 10 | 2 | 744204 | 5267862 |
| 11 | 2 | 609022 | 5876884 |
| ... | ... | ... | ... |
+------------+---------+--------+----------------+
20000 rows in set (19.2161 sec.)
现在,我使用以下查询来获得上述结果
SELECT
a.fileInfoId
, a.groupId
, a.size
, SUM(b.size) AS cumulativeSize
FROM fileInfo AS a
LEFT JOIN fileInfo AS b USING(groupId)
WHERE a.fileInfoId >= b.fileInfoId
GROUP BY a.fileInfoId
ORDER BY a.groupId, a.fileInfoId
但是,我的解决方案非常缓慢。 (大约 19 秒没有缓存)。
解释给出以下执行细节
+----+--------------+-------+-------+-------------------+-----------+---------+----------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+-------+-------+-------------------+-----------+---------+----------------+-------+-------------+
| 1 | SIMPLE | a | index | PRIMARY,foreignId | PRIMARY | 4 | NULL | 14905 | |
| 1 | SIMPLE | b | ref | PRIMARY,foreignId | foreignId | 4 | db.a.foreignId | 36 | Using where |
+----+--------------+-------+-------+-------------------+-----------+---------+----------------+-------+-------------+
我的问题是:
如何优化上述查询?
更新
我已经更新了问题,以提供表结构和用 20,000 条记录测试数据填充表的过程。
CREATE TABLE `fileInfo` (
`fileInfoId` int(10) unsigned NOT NULL AUTO_INCREMENT
, `groupId` int(10) unsigned NOT NULL
, `name` varchar(128) NOT NULL
, `size` int(10) unsigned NOT NULL
, PRIMARY KEY (`fileInfoId`)
, KEY `groupId` (`groupId`)
) ENGINE=InnoDB;
delimiter $$
DROP PROCEDURE IF EXISTS autofill$$
CREATE PROCEDURE autofill()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE gid INT DEFAULT 0;
DECLARE nam char(20);
DECLARE siz INT DEFAULT 0;
WHILE i < 20000 DO
SET gid = FLOOR(RAND() * 250);
SET nam = CONV(FLOOR(RAND() * 10000000000000), 20, 36);
SET siz = FLOOR((RAND() * 1024 * 1024));
INSERT INTO `fileInfo` (`groupId`, `name`, `size`) VALUES(gid, nam, siz);
SET i = i + 1;
END WHILE;
END;$$
delimiter ;
CALL autofill();
关于可能重复的问题
Forgotten Semicolon 链接的The question 不是同一个问题。我的问题有额外的专栏。由于这个额外的 groupId 列,那里接受的答案不适用于我的问题。 (也许它可以适应工作,但我不知道如何,因此我的问题)
【问题讨论】:
-
我没有时间,但有可能(使用 ROLLUP)[dev.mysql.com/doc/refman/5.1/en/group-by-modifiers.html] 将做你想做的事,而无需自我加入......
-
@OMG Ponies 如果你有时间回答,我会很想看看 With Rollup 解决方案。
-
不能保证它会更快,但如果您可以使用脚本更新问题以创建表格并填充它 - 这会有所帮助。
-
WITH ROLLUP非常快。它将进行汇总,在对每个组求和后添加一个总计行,但我不知道如何让它产生一个运行总计。如果可以做到,那将是一个很好的解决方案。
标签: sql mysql query-optimization