postgresql / sql - 改进查询,其中相同的子选择用于IN&不是选择

时间:2014-08-02 12:11:53

标签: sql postgresql

如何改进此查询。问题是相同的子选择使用了两次,首先是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 )
)

3 个答案:

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