MySQL:检测大型连接表中至少存在1条记录

时间:2017-06-02 11:37:27

标签: mysql sql join

我有两张桌子:

用户(身份证,姓名)

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;

提前致谢!

4 个答案:

答案 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