如何改进此查询。问题是相同的子选择使用了两次,首先是IN
,然后是NOT IN
:
SELECT
"activities".*
FROM "activities"
WHERE (
user_id IN (
SELECT followed_id
FROM relationships
WHERE follower_id = 1 AND blocked = false)
AND
targeted_user_id NOT IN (
SELECT followed_id
FROM relationships
WHERE follower_id = 1 AND blocked = false )
)
答案 0 :(得分:1)
使用公用表表达式将有所帮助:
WITH users_cte AS (
SELECT followed_id
FROM relationships
WHERE follower_id = 1 AND blocked = false)
SELECT "activities.*"
FROM "activities"
WHERE user_id IN (SELECT followed_id FROM users_cte)
AND targeted_user_id NOT IN (SELECT followed_id FROM users_cte)
答案 1 :(得分:0)
我会使用exists
:
SELECT a.*
FROM activities a
WHERE EXISTS (SELECT 1
FROM relationships r
WHERE r.followed_id = a.user_id AND
r.follower_id = 1 and
r.blocked = false
) AND
NOT EXISTS (SELECT 1
FROM relationships r
WHERE r.followed_id = a.targeted_user_id AND
r.follower_id = 1 and
r.blocked = false
);
然后,我会在relationships(followed_id, follower_id, blocked)
上创建一个索引:
create index idx_relationships_3 on relationships(followed_id, follower_id, blocked);
从性能角度来看,索引应该比使用CTE好得多(如果你真的使用Postgres,MySQL不支持CTE)。
答案 2 :(得分:0)
除索引外,您还可以尝试重写查询,如下所示:
SELECT distinct a.*
FROM activities a
join relationships x
on a.user_id = x.followed_id
left join relationships r
on a.targeted_user_id = r. followed_id
and r.follower_id = 1
and r.blocked = false
where r.followed_id is null
and x.follower_id = 1
and x.blocked = false
如果上面关系(x)的内部联接不会导致重复的活动行,则可以摆脱DISTINCT。