【问题标题】:How to efficiently sort by the results of a subquery?如何有效地按子查询的结果排序?
【发布时间】:2020-02-19 17:57:49
【问题描述】:

假设我有一个像 Stackoverflow 这样的网站,其中包含人们可以回复的帖子,我想要一个界面来按回复计数对帖子进行排序

这最终会有无限滚动分页,所以一次显示10个结果。

这是一个示例查询:

SELECT *, (SELECT COUNT(*) 
           FROM post_reply pr 
           WHERE pr.convo_id = post.convo_id) as replies 
FROM post 
ORDER BY replies 
LIMIT 10;

这行得通,但速度太慢了。我有数十万个帖子,这导致查询需要 30 秒才能完成。

索引会提高速度,但我不知道如何在子查询上实现索引。

物化视图也可以工作,但每次有人回复帖子时更新物化视图似乎也太慢了。

这个问题有好的解决办法吗?

【问题讨论】:

  • 索引是物理数据结构,它们不存在于查询级别(除了会强制使用特定索引的查询提示)。也就是说,索引是在表上创建的,而不是子查询。您能否提供现有的表结构(如 CREATE 语句)?在 SQL Server 中,引擎将使用最小/最窄的索引来进行 COUNT。我不确定它在 postgres 中是否相同。
  • @JacobH 表结构并不多。 postpost_reply 都具有 convo_id 字段(一对多关系),并且它们都具有 TEXT 正文字段。还有其他一些专栏,但它们与这个问题并不太相关。

标签: sql postgresql performance indexing sql-order-by


【解决方案1】:

你不能真正加快这个查询。

您可以更改数据模型并使用大量基础架构来获得更快的排序。这个想法是:

  1. posts 表中添加一列post_reply_count
  2. 在此列上添加索引。
  3. 使用触发器使此列保持最新 -- + 1 用于 insert- 1 用于 delete。以及适合update 的任何内容。
  4. 在查询中使用此列。

这会增加开销。但如果你真的需要快速响应这个查询,你可能别无选择。

【讨论】:

  • 听起来不错,但我真的不知道触发器的性能如何。我想我得用谷歌搜索一下。对于触发器的偏好与运行每 10 分钟左右更新所有帖子及其各自帖子数的作业的偏好有何意见?
  • @RyanPeschel 。 . .基本上,它们为每个 DML 操作增加了一点开销。除非您的数据库负载很重,否则您可能不会注意到它。
【解决方案2】:

您可以更改查询顺序并首先按回复计数生成帖子列表,然后获取post 列。这应该使用主键(我假设 post.convo_id 是一个)并且可能会更快,但我不保证会这样做。

SELECT post.*, sub.replies
  FROM (SELECT pr.convo_id, COUNT(*) AS replies
          FROM post_reply pr
         GROUP BY pr.convo_id
         ORDER BY replies --maybe DESC if you want top reply count first
         LIMIT 10
       ) AS sub
  JOIN post USING(convo_id);

【讨论】:

  • 从 30 秒到 3 毫秒。非常聪明!
  • @RyanPeschel 这是奇怪的变化。也许您在post_reply.convo_id 上没有索引?我确实在具有一对多关系的表上尝试了这种方法,并且确实有一些速度提高(比如 20%),但我将其归因于在“多”表上使用多列索引。或者我只是有完全不同的数据集(没有 cmets/posts 表)。
猜你喜欢
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 2015-11-06
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
相关资源
最近更新 更多