Подсчет по состоянию нескольких внутренних соединений в PostgreSQL - PullRequest
0 голосов
/ 22 февраля 2019

У меня есть следующие таблицы:

User
UserPostView
Post

UserPostView - это таблица соединений, содержащая дополнительную информацию о том, User проголосовал, понизил или прошел после просмотра сообщения.

Post содержит столбец postable_type, указывающий тип сообщения (TextPost, ImagePost и т. Д.).

Я хотел бы рассчитать количество голосов «за», «против» и «пройдено» для каждого пользователя, сгруппированного по postable_type.

Мой текущий запрос очень медленный, и я уверен, что его можно легко оптимизировать.

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

1 Ответ

0 голосов
/ 22 февраля 2019

Не делайте преобразования типов для объединений!Я думаю, вам просто нужно:

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 немного быстрее, чем условныйагрегация.Что еще более важно, намерение яснее.
...