【发布时间】:2020-02-20 10:59:02
【问题描述】:
我有一个永远运行的 MySQL (v5.7.26) 查询。这是查询:
SELECT
ur.user_id AS user_id,
sum(r.duration) AS total_time,
count(user_id) AS number_of_workouts
FROM user_resource ur
INNER JOIN resource r ON r.id = ur.resource_id
WHERE
ur.status = 1
AND NOT ur.action_date IS NULL
AND ur.user_id IN (
SELECT user_id
FROM user_resource ur2
WHERE ur2.action_date >= now() - INTERVAL 2 DAY
)
AND r.type = 'WORKOUT'
GROUP BY ur.user_id;
通过尝试了解问题出在哪里,我已经玩了一点。出于测试目的,我尝试分成两个。所以:
SELECT user_id
FROM user_resource ur2
WHERE ur2.action_date >= now() - INTERVAL 2 DAY;
返回(很快)用户 user_id 的列表。 当我将返回的结果插入查询的第一部分时,如下所示:
SELECT
ur.user_id AS user_id,
sum(r.duration) AS total_time,
count(user_id) AS number_of_workouts
FROM user_resource ur
INNER JOIN resource r ON r.id = ur.resource_id
WHERE
ur.status = 1
AND NOT ur.action_date IS NULL
AND ur.user_id IN (1,1,1,4,4,5,6,7,7,7);
AND r.type = 'WORKOUT'
GROUP BY ur.user_id
它运行得非常快。我的假设是 IN(子查询)是瓶颈。
我正在考虑提取子查询并获取 user_ids,然后将其用作变量,但我不确定这是不是好方法,另外我遇到了问题。这是我的尝试:
-- first statement
SET @v1 = (SELECT user_id
FROM user_resource ur2
WHERE ur2.action_date >= now() - INTERVAL 2 DAY)
-- second statement
SELECT
ur.user_id AS user_id,
sum(r.duration) AS total_time,
count(user_id) AS prefixes
FROM user_resource ur
INNER JOIN resource r ON r.id = ur.resource_id
WHERE
ur.status = 1
AND NOT ur.action_date IS NULL
AND ur.user_id IN (@v1);
AND r.type = 'WORKOUT'
GROUP BY ur.user_id
这里的问题是first statement返回错误:
子查询返回多于 1 行。
预期结果是 user_id,可以是重复的。我需要那些重复的。
我该如何解决这个问题?
【问题讨论】:
-
我想知道为什么您的查询首先运行缓慢,尽管子查询很快并且替换值很快。您是否尝试将
group by ur2.user_id添加到您的子查询中? -
是的,我试过了。结果相同。 DB是RDS,大内存
-
AND NOT ur.action_date IS NULL 有点不和谐,为什么不 AND ur.action_date IS NOT NULL? (不要认为这与性能有任何关系,它只会冒犯我)
-
请发布 DDL 和查询计划
-
INDEX(action_date, user_id)可能会有所帮助。请为两张表提供SHOW CREATE TABLE。