Mysql返回最后一个活动早于X天的ID

时间:2018-02-21 13:08:10

标签: php mysql performance

我有一个记录每个用户活动的日志表。

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查询中获取所有内容?

2 个答案:

答案 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语句返回10,具体取决于过去30天内用户活动中是否至少有一条记录。因此,对于每个用户,字段Active已正确更新为10

  

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的记录。

由于您的事件表会随着时间的推移无限增长,您应该考虑定期删除旧条目或将它们移动到单独的表/转储文件中。