我有两张桌子:
用户(身份证,姓名)
user_activities(id,user_id,activity_id,created_at)
user_activities表非常大,超过3亿行。
我正在尝试检测哪些用户在给定的日期范围之间进行了任何活动。换句话说,用户表上的行,其中某个created_at范围之间的user_activities表中存在连接的行。
我可以使用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;
提前致谢!
答案 0 :(得分:1)
您可以尝试以下版本:
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;
对于性能,您需要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'
);
虽然您的查询执行复杂处理然后聚合一堆数据,但这应扫描users
表,并在索引中查找用户是否存在适当的活动。
答案 1 :(得分:1)
使用EXISTS
子句,因此DBMS认为在给定的日期范围内找到每个用户一条记录就足够了。
SELECT id, name
FROM users u
where exists
(
select *
from user_activity ua
where ua.user_id = u.id
and ua.created_at > '2017-01-01' AND ua.created_at < '2017-03-01'
);
使用此索引:
create index idx on user_activity(user_id, created_at);
答案 2 :(得分:0)
获取已完成特定日期范围活动的用户
select u.id, u.name from users u
where exists ( SELECT 1 FROM user_activity ua
where ua.user_id = u.id
and ua.created_at > '2017-01-01' AND
ua.created_at < '2017-03-01')
为user_activity创建索引(created_at)
答案 3 :(得分:0)
如果仅用于测试存在,那么:
SELECT EXISTS(
SELECT u.id
FROM user_activity AS ua
WHERE u.id = ua.user_id
AND ua.created_at > '2017-01-01'
AND ua.created_at < '2017-03-01'
) AS ret
这将只返回列 ret = 1 如果至少一行查询将满足给定条件,否则它将返回列 ret = 0