我有一个记录每个用户活动的日志表。
UserActivityTable(15Milion记录)
id userID category value timestamp
1 2 Visit homepage 2018-02-21 13:13:54
1 2 Visit page2 2018-02-18 13:13:45
1 2 Visit page1 2018-02-15 13:13:30
1 3 Visit homepage 2018-02-01 13:13:12
使用SQL查询我需要获取所有用户ID,如果用户设置为“活动”,则最后一个活动的时间早于X天(假设为30)
用户(15k用户)
id Groups Active Name Mails ...
2 Customer 1 Hans
3 Customer 0 Wurst
如果我让所有用户都活跃(大约5k)并且试图到达最后一次活动我会遇到超时(我认为查询不是性能) 如果我将它限制为5则没有问题。
我尝试的是什么。
1选择所有活动的用户,而不是使用foreach函数来获取最后一个活动,如果超过30天我将其写入新数组中,最后我使用该数组来设置用户表中的活动为假。
直到过去的2-3个月,它很好,但现在我们有很多新用户,而且功能无法处理它。
是否有一种干净的方法可以在一个SQL查询中获取所有内容?
答案 0 :(得分:2)
您可以使用以下查询来获取Users
:
SELECT `userID`, MAX(`timestamp`) AS lastActive FROM `UserActivityTable`
WHERE `userID` IN (
SELECT `id` FROM `Users` WHERE `Active` = 1
) GROUP BY `userID` HAVING lastActive < DATE_SUB(NOW(), INTERVAL 30 DAY)
<强>索引强>
Users
表格上使用PRIMARY KEY
索引。UserActivityTable
表格上使用FOREIGN KEY
索引。timestamp
列上创建列索引。您可以使用以下内容在timestamp
列上创建INDEX
:
CREATE INDEX index_timestamp ON `UserActivityTable` (`timestamp`);
您还可以在UPDATE
表格上使用active
Users
状态的单个查询:
UPDATE `Users` SET `active` = EXISTS (
SELECT `userID` FROM `UserActivityTable` WHERE `UserActivityTable`.`userID` = `Users`.`id` GROUP BY `UserActivityTable`.`userID` HAVING MAX(`UserActivityTable`.`timestamp`) > DATE_SUB(NOW(), INTERVAL 30 DAY)
)
答案 1 :(得分:1)
是否有一种干净的方法可以在一个SQL查询中获取所有内容?
是,您可以使用以下查询一步更新 Users
表:
UPDATE `Users` SET `Active` = EXISTS(
SELECT * from `UserActivityTable ` WHERE
`UserActivityTable `.`userID` = `Users`.`id` AND
`timestamp`>DATE_SUB( NOW(), INTERVAL 30 DAY )
)
EXISTS
语句返回1
或0
,具体取决于过去30天内用户活动中是否至少有一条记录。因此,对于每个用户,字段Active
已正确更新为1
或0
。
Mysql返回上次活动早于X天的回复ID
如果您只想要具有活动的用户ID列表:
SELECT `Users`.`id` WHERE EXISTS(
SELECT * from `UserActivityTable ` WHERE
`UserActivityTable `.`userID` = `Users`.`id` AND
`timestamp`>DATE_SUB( NOW(), INTERVAL 30 DAY )
) = 1
为了获得良好的表现(至少),必须将字段timestamp
编入索引。
旁注
你已经达到了15M的记录。
由于您的事件表会随着时间的推移无限增长,您应该考虑定期删除旧条目或将它们移动到单独的表/转储文件中。