Bạn có thể sử dụng một biến - nó nhanh hơn nhiều so với bất kỳ phép nối nào:
SELECT
id,
size,
@total := @total + size AS cumulativeSize,
FROM table, (SELECT @total:=0) AS t;
Đây là một trường hợp kiểm tra nhanh trên Pentium III với 128MB RAM chạy Debian 5.0:
Tạo bảng:
DROP TABLE IF EXISTS `table1`;
CREATE TABLE `table1` (
`id` int(11) NOT NULL auto_increment,
`size` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Điền với 20.000 số ngẫu nhiên:
DELIMITER //
DROP PROCEDURE IF EXISTS autofill//
CREATE PROCEDURE autofill()
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < 20000 DO
INSERT INTO table1 (size) VALUES (FLOOR((RAND() * 1000)));
SET i = i + 1;
END WHILE;
END;
//
DELIMITER ;
CALL autofill();
Kiểm tra số lượng hàng:
SELECT COUNT(*) FROM table1;
+----------+
| COUNT(*) |
+----------+
| 20000 |
+----------+
Chạy truy vấn tổng tích lũy:
SELECT
id,
size,
@total := @total + size AS cumulativeSize
FROM table1, (SELECT @total:=0) AS t;
+-------+------+----------------+
| id | size | cumulativeSize |
+-------+------+----------------+
| 1 | 226 | 226 |
| 2 | 869 | 1095 |
| 3 | 668 | 1763 |
| 4 | 733 | 2496 |
...
| 19997 | 966 | 10004741 |
| 19998 | 522 | 10005263 |
| 19999 | 713 | 10005976 |
| 20000 | 0 | 10005976 |
+-------+------+----------------+
20000 rows in set (0.07 sec)
CẬP NHẬT
Tôi đã bỏ lỡ việc phân nhóm theo nhómId trong câu hỏi ban đầu, và điều đó chắc chắn khiến mọi thứ phức tạp hơn một chút. Sau đó, tôi đã viết một giải pháp sử dụng một bảng tạm thời, nhưng tôi không thích nó — nó lộn xộn và quá phức tạp. Tôi đã đi xa và thực hiện thêm một số nghiên cứu và đã nghĩ ra một thứ gì đó đơn giản hơn và nhanh hơn nhiều.
Tôi không thể yêu cầu tất cả tín dụng cho điều này — trên thực tế, tôi hầu như không thể yêu cầu bất kỳ điều gì, vì nó chỉ là phiên bản sửa đổi của Mô phỏng số hàng từ Truy vấn MySQL Phổ biến .
Nó rất đơn giản, trang nhã và rất nhanh chóng:
SELECT fileInfoId, groupId, name, size, cumulativeSize
FROM (
SELECT
fileInfoId,
groupId,
name,
size,
@cs := IF(@prev_groupId = groupId, @cs+size, size) AS cumulativeSize,
@prev_groupId := groupId AS prev_groupId
FROM fileInfo, (SELECT @prev_groupId:=0, @cs:=0) AS vars
ORDER BY groupId
) AS tmp;
Bạn có thể xóa SELECT ... AS tmp
bên ngoài nếu bạn không nhớ prev_groupID
cột được trả về. Tôi thấy rằng nó chạy nhanh hơn một chút khi không có nó.
Đây là một trường hợp thử nghiệm đơn giản:
INSERT INTO `fileInfo` VALUES
( 1, 3, 'name0', '10'),
( 5, 3, 'name1', '10'),
( 7, 3, 'name2', '10'),
( 8, 1, 'name3', '10'),
( 9, 1, 'name4', '10'),
(10, 2, 'name5', '10'),
(12, 4, 'name6', '10'),
(20, 4, 'name7', '10'),
(21, 4, 'name8', '10'),
(25, 5, 'name9', '10');
SELECT fileInfoId, groupId, name, size, cumulativeSize
FROM (
SELECT
fileInfoId,
groupId,
name,
size,
@cs := IF(@prev_groupId = groupId, @cs+size, size) AS cumulativeSize,
@prev_groupId := groupId AS prev_groupId
FROM fileInfo, (SELECT @prev_groupId := 0, @cs := 0) AS vars
ORDER BY groupId
) AS tmp;
+------------+---------+-------+------+----------------+
| fileInfoId | groupId | name | size | cumulativeSize |
+------------+---------+-------+------+----------------+
| 8 | 1 | name3 | 10 | 10 |
| 9 | 1 | name4 | 10 | 20 |
| 10 | 2 | name5 | 10 | 10 |
| 1 | 3 | name0 | 10 | 10 |
| 5 | 3 | name1 | 10 | 20 |
| 7 | 3 | name2 | 10 | 30 |
| 12 | 4 | name6 | 10 | 10 |
| 20 | 4 | name7 | 10 | 20 |
| 21 | 4 | name8 | 10 | 30 |
| 25 | 5 | name9 | 10 | 10 |
+------------+---------+-------+------+----------------+
Đây là ví dụ về một vài hàng cuối cùng từ bảng 20.000 hàng:
| 19481 | 248 | 8CSLJX22RCO | 1037469 | 51270389 |
| 19486 | 248 | 1IYGJ1UVCQE | 937150 | 52207539 |
| 19817 | 248 | 3FBU3EUSE1G | 616614 | 52824153 |
| 19871 | 248 | 4N19QB7PYT | 153031 | 52977184 |
| 132 | 249 | 3NP9UGMTRTD | 828073 | 828073 |
| 275 | 249 | 86RJM39K72K | 860323 | 1688396 |
| 802 | 249 | 16Z9XADLBFI | 623030 | 2311426 |
...
| 19661 | 249 | ADZXKQUI0O3 | 837213 | 39856277 |
| 19870 | 249 | 9AVRTI3QK6I | 331342 | 40187619 |
| 19972 | 249 | 1MTAEE3LLEM | 1027714 | 41215333 |
+------------+---------+-------------+---------+----------------+
20000 rows in set (0.31 sec)