按PostgreSQL中多个内连接的条件计算

问题描述 投票:0回答:1

我有以下表格:

User UserPostView Post

UserPostView是一个联接表,其中包含有关User在查看帖子后是否上调,下注或通过的其他信息。

Post有一个postable_type列,表明帖子的类型(TextPostImagePost等)。

我想计算由postable_type分组的每个用户的upvotes,downvotes和pass count。

我当前的查询非常慢,我很确定它可以很容易地进行优化。

SELECT
    U.id,
    count((UP.postable_type = 'text_post' AND UPV.passed = true) OR NULL) as text_posts_pass_count,
    count((UP.postable_type = 'text_post' AND UPV.upvote = true) OR NULL) as text_posts_upvote_count,
    count((UP.postable_type = 'text_post' AND UPV.downvote = true) OR NULL) as text_posts_downvote_count,
    count((UP.postable_type = 'image_post' AND UPV.passed = true) OR NULL) as image_posts_pass_count,
    count((UP.postable_type = 'image_post' AND UPV.upvote = true) OR NULL) as image_posts_upvote_count,
    count((UP.postable_type = 'image_post' AND UPV.downvote = true) OR NULL) as image_posts_downvote_count
FROM
    users U
    INNER JOIN(
        SELECT
            user_id,
            post_id,
            passed,
            upvoted,
            downvoted
        FROM 
            user_post_views
    ) UPV on U.id :: TEXT = UPV.user_id :: TEXT
    INNER JOIN(
        SELECT
            id,
            postable_type
        FROM
            posts
    ) UP on UPV.post_id :: TEXT = UP.id :: TEXT
GROUP BY
    U.id
sql postgresql join group-by window-functions
1个回答
1
投票

不要为连接进行类型转换!我想你只需要:

SELECT UPV.user_id,
       COUNT(*) FILTER (WHERE p.postable_type = 'text_post' AND upv.passed) as text_posts_pass_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'text_post' AND upv.upvote) as text_posts_upvote_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'text_post' AND upv.downvote ) as text_posts_downvote_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'image_post' AND upv.passed) as image_posts_pass_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'image_post' AND upv.upvote) as image_posts_upvote_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'image_post' AND upv.downvote) as image_posts_downvote_count
FROM user_post_views upv JOIN
     posts p
     ON upv.post_id = p.id 
GROUP BY upv.user_id;

变化:

  • 不要为连接进行类型转换!这肯定会阻碍优化器。
  • users表似乎没有必要。
  • 子查询不是必需的。
  • FILTER比条件聚合略快。更重要的是,意图更加清晰。
© www.soinside.com 2019 - 2024. All rights reserved.