我有一个名为页面加载的表,其中包含以下列
user_id
timestamp
country
city
该表有3700万条记录,两列都有索引
时间戳范围为7/23到9/27
我需要做的是:对于8/24到9/27的日期范围,请计算每天不同用户在过去30天内不存在的情况。
因此,对于8/24中存在的表中的用户,查找7/23和8/23之间不存在于表中的不同用户的计数。在8月24日至9月27日期间,每天都需要做同样的事情。
select
count(distinct user_id)
from
pageloads
where
user_id not in (select user_id from pageloads where time between
'2015-07-24 00:00:00' and '2015-08-23 23:59:59')
and left(time,10) = '2015-08-24'
由于不是in子句,这种方法非常慢,并且一次只能运行1天。
请有人帮助我。
答案 0 :(得分:0)
尝试使用
AND NOT EXIST ( select 1 from pageloads p1 where p1.time between
'2015-07-24 00:00:00' and '2015-08-23 23:59:59' and p1.user_id = user_id)
NOT EXIST非常有效,因为它在找到1条记录时停止搜索。如果没有记录,那么它也会立即被发现。 user_id的索引也可以使用。
答案 1 :(得分:0)
IN子句非常慢。更好地使用临时表和连接,它的速度要快得多。
答案 2 :(得分:0)
我做了一些测试,找到了最好的解决方案。我现在没有多久会生成这个报告,但如果你使用新的累积表我会得到最好的结果。
在此表中,您可以存储每天/用户的累计值,如果您想在第二天生成报告,则只需要使用一天的数据更新新表。
新表格
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));
如果您想要报告,请立即告诉我。