我有两张桌子:
用户(ID、姓名)
用户活动(id、user_id、activity_id、created_at)
user_activities 表非常大,有超过 3 亿行。
我试图检测哪些用户在给定日期范围内进行了任何活动。换句话说,用户表上的行,其中 user_activities 表上存在某个已创建的_at 范围之间的连接行。
我可以使用 INNER JOIN、GROUP BY 和 WHERE 子句来执行此操作,但查询会运行很长时间,因为我相信它会命中我的日期范围内的所有 user_activities 行。
我并不真正关心“有多少”活动,只要它们的活动数量是否超过零即可。因此,我分组以获取计数(例如 210 个活动),而实际上我可以在仅找到 1 个后停止。
有没有更有效的方法来执行此操作,而不是对所有 user_activity 行进行分组来对其进行计数?
有关信息,这是当前的查询,它工作正常但需要很长时间:
SELECT u.id, u.name, COUNT(ua.id) AS activity_count
FROM users u
INNER JOIN user_activity ua ON u.id=ua.user_id
WHERE ua.created_at > '2017-01-01' AND ua.created_at < '2017-03-01'
GROUP BY u.id
HAVING activity_count > 0;
Run Code Online (Sandbox Code Playgroud)
提前致谢!
您可以尝试这个版本:
SELECT u.id, u.name,
(SELECT COUNT(*)
FROM user_activity ua
WHERE u.id = ua.user_id AND
ua.created_at > '2017-01-01' AND
ua.created_at < '2017-03-01'
) as activity_count
FROM users u
HAVING activity_count > 0;
Run Code Online (Sandbox Code Playgroud)
为了提高性能,您需要在 上建立索引user_activity(user_id, created_at)。
编辑:
如果你只是想要存在,那么使用相同的索引,这应该会快得多:
SELECT u.id, u.name
FROM users u
WHERE EXISTS (SELECT 1
FROM user_activity ua
WHERE u.id = ua.user_id AND
ua.created_at > '2017-01-01' AND
ua.created_at < '2017-03-01'
);
Run Code Online (Sandbox Code Playgroud)
尽管您的查询会进行复杂的处理,然后聚合一堆数据,但它应该扫描表users,并仅在索引中查找是否存在适合用户的适当活动。