我进行了一些测试,并找到了最好的解决方案。我现在不知道您多久生成一次此报告,但如果您使用新的累积表,我会得到最好的结果。
在此表中,您存储每天/用户的累计值,如果您想在第二天生成报告,只需使用一天的数据更新新表。
新表格
CREATE TABLE `pageload_cum` (
`user_id` INT(11) NOT NULL DEFAULT '0',
`time` DATE,
`quantity` INT(11) DEFAULT NULL,
PRIMARY KEY (`user_id`,`time`),
KEY `time` (`time`,`user_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
填表
此查询将插入过去 60 天的所有数据,这些数据将用于从昨天开始的报告。如果你明天开始它只会产生
失踪的一天
INSERT IGNORE INTO pageload_cum
SELECT DISTINCT p.user_id ,
DATE(p.`time`),
SUM(1) AS quantity
FROM pageloads p
WHERE
DATE(p.`time`) NOT IN (
SELECT DISTINCT p.time FROM pageload_cum p
)
AND p.`time` > SUBDATE(NOW(), INTERVAL 61 DAY)
AND p.`time` < SUBDATE(NOW(), INTERVAL 1 DAY)
GROUP BY DATE(p.`time`), p.user_id;
现在是报告
报告会生成一些仅用于了解结果的列。如果您不使用它们,您可以删除它们。对于一列“group_concat_max_len”,需要将变量设置为保存完整结果的大小。您可以在查询之前设置它,也可以直接在 my.cnf 中设置。
SET group_concat_max_len=16384;
SELECT
DATE(p.`time`) checkdate,
DATE(SUBDATE(`p`.`TIME`, INTERVAL 31 DAY)) AS hist_start,
DATE(SUBDATE(`p`.`TIME`, INTERVAL 1 DAY)) AS hist_end,
sum(1) AS cnt_user,
GROUP_CONCAT(DISTINCT p.user_id SEPARATOR ', ') user_not_hist
FROM pageload_cum p
LEFT JOIN pageload_cum hist
ON `hist`.`TIME` BETWEEN DATE(SUBDATE(`p`.`TIME`, INTERVAL 31 DAY)) AND DATE(SUBDATE(`p`.`TIME`, INTERVAL 1 DAY))
AND p.user_id = hist.user_id
WHERE
hist.user_id IS NULL
AND
`p`.`TIME` BETWEEN '2015-09-01 00:00:00' AND '2015-09-30 23:59:59'
GROUP BY DATE(`p`.`TIME`);
结果
我仅在页面加载表中使用 10.000.000 行测试了此查询,并为此结果更改了一些数据。
+------------+------------+------------+----------+--------------------------+
| checkdate | hist_start | hist_end | cnt_user | user_not_hist |
+------------+------------+------------+----------+--------------------------+
| 2015-09-13 | 2015-08-13 | 2015-09-12 | 1 | 3333 |
| 2015-09-27 | 2015-08-27 | 2015-09-26 | 4 | 4567, 5678, 12345, 31313 |
+------------+------------+------------+----------+--------------------------+
2 rows in set (0.29 sec)
最少的
没有必要删除孔表。您只能删除您不再使用的日子里的旧数据,例如
DELETE FROM pageload_cum WHERE `time` < DATE(SUBDATE(now(), INTERVAL 100 DAY));
如果你想要报告,请现在告诉我。