【问题标题】:Is it possible to improve the performance of this subquery?是否可以提高此子查询的性能?
【发布时间】:2019-12-29 23:26:26
【问题描述】:

对于我的应用程序,我有一个主题表和一个投票表。投票选项是 -1、0 和 1。我试图找出每个主题被投票 -1 和 1 的次数。

所以要找出来,我做了很多子查询,每个子查询都使用find total number of -1 or 1 votes and then divide by the total number of votes的算法。

不幸的是,我想出的东西很慢。部分原因是我计算了两次计数,但我不确定是否可以从外部查询中引用它。

这个性能可以提高吗?

SELECT title,
  (SELECT COUNT(vote)::float8 FROM vote WHERE topic_id = v1.topic_id AND vote_choice = -1) 
/ (SELECT COUNT(vote)::float8 FROM vote WHERE topic_id = v1.topic_id) as lp,
  (SELECT COUNT(vote)::float8 FROM vote WHERE topic_id = v1.topic_id AND vote_choice = 1) 
/ (SELECT COUNT(vote)::float8 FROM vote WHERE topic_id = v1.topic_id) as rp
FROM topic
JOIN vote v1 ON topic.id = v1.topic_id 
GROUP BY v1.topic_id, topic.title;

【问题讨论】:

  • 是否要求所有数据都在 1 行中?您可以将其更改为SELECT vote_choice, COUNT(vote_choice),并在组中添加vote_choice。但是,每个 vote_choice 都会有 1 行的计数。
  • 我并没有真正关注你。一个主题可以有很多票,所以我必须按主题而不是投票选项来分组。
  • 我很想说重写相关的子查询以使用连接来代替..但是没有表结构和我们知道的很少的解释来提供有效的建议..

标签: sql postgresql query-optimization aggregation


【解决方案1】:

我会使用FILTER 而不是相关子查询:

SELECT 
    title,
    1.0 * COUNT(*) FILTER(WHERE vote_choice = -1) / COUNT(*) as lp,
    1.0 * COUNT(*) FILTER(WHERE vote_choice = 1)  / COUNT(*) as rp
FROM topic
JOIN vote v1 ON topic.id = v1.topic_id 
GROUP BY v1.topic_id, topic.title;

【讨论】:

  • 我认为 COUNT(vote) 应该是 COUNT(v1) (因为您不再从子查询中选择,而是从别名为 v1vote 中选择),但效果很好(我重新创建了他的本地结构)
  • @Mark 是的,我同意。 * 是这里最安全的选择。
  • 谢谢。这将性能提高了 10 倍。我以前从未听说过FILTER 关键字。我会做一些阅读。
  • @RyanPeschel 听到它真的很棒:)
【解决方案2】:

根据您的描述,这可以使用条件聚合来完成:

select title, 
       count(vote) as total_count,
       count(vote)::numeric filter (where vote_choice = -1) / count(vote)::numeric as lp,
       count(vote)::numeric filter (where vote_choice = 1) / count(vote) as rp
from topic t
  join vote v on t.id = v.topic_id
group by title;

【讨论】:

  • 伟大的思想都一样。很遗憾,我只能接受一个答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 2016-04-06
  • 1970-01-01
  • 2020-04-21
  • 2019-03-20
相关资源
最近更新 更多