【问题标题】:PostgreSQL Query with many:many join is very slow具有多:多连接的PostgreSQL查询非常慢
【发布时间】:2019-11-25 23:56:31
【问题描述】:

问题:我需要找到带有指定 Hashtag 的帖子。 many:many 连接表称为 PostHashtag。但是,看起来内部连接太慢了:

EXPLAIN ANALYZE SELECT
    "Post"."id",
    "Post"."createdAt",
    "Post"."photo",
    "Post"."thumbnail",
    "hashtags->PostHashtag"."id" AS "hashtags.PostHashtag.id",
    "hashtags->PostHashtag"."hashtagId" AS "hashtags.PostHashtag.hashtagId",
    "hashtags->PostHashtag"."postId" AS "hashtags.PostHashtag.postId",
    "hashtags->PostHashtag"."createdAt" AS "hashtags.PostHashtag.createdAt",
    "hashtags->PostHashtag"."updatedAt" AS "hashtags.PostHashtag.updatedAt"
FROM
    "Posts" AS "Post"
INNER JOIN (
    "PostHashtags" AS "hashtags->PostHashtag"
    INNER JOIN "Hashtags" AS "hashtags" ON "hashtags"."id" = "hashtags->PostHashtag"."hashtagId"
) ON "Post"."id" = "hashtags->PostHashtag"."postId"
AND "hashtags"."name" = 'pumpupfam'
WHERE
    "Post"."photo" IS NOT NULL
AND "Post"."private" IS NULL
ORDER BY
    "Post"."createdAt" DESC
LIMIT 90;

产量

Limit  (cost=2651.58..2651.60 rows=7 width=212) (actual time=349.987..350.048 rows=90 loops=1)
  ->  Sort  (cost=2651.58..2651.60 rows=7 width=212) (actual time=349.985..350.013 rows=90 loops=1)
        Sort Key: "Post"."createdAt"
        Sort Method: top-N heapsort  Memory: 48kB
        ->  Nested Loop  (cost=18.80..2651.49 rows=7 width=212) (actual time=9.125..336.449 rows=30092 loops=1)
              ->  Nested Loop  (cost=18.37..2623.52 rows=19 width=28) (actual time=9.096..93.508 rows=31495 loops=1)
                    ->  Index Scan using hashtags_name_unique_index on "Hashtags" hashtags  (cost=0.42..8.44 rows=1 width=4) (actual time=0.034..0.036 rows=1 loops=1)
                          Index Cond: ((name)::text = 'pumpupfam'::text)
                    ->  Bitmap Heap Scan on "PostHashtags" "hashtags->PostHashtag"  (cost=17.94..2607.97 rows=711 width=28) (actual time=9.059..79.563 rows=31495 loops=1)
                          Recheck Cond: ("hashtagId" = hashtags.id)
                          Heap Blocks: exact=21507
                          ->  Bitmap Index Scan on posthashtags_hashtagid_fk_index  (cost=0.00..17.77 rows=711 width=0) (actual time=5.393..5.393 rows=31496 loops=1)
                                Index Cond: ("hashtagId" = hashtags.id)
              ->  Index Scan using "Posts_pkey" on "Posts" "Post"  (cost=0.43..1.46 rows=1 width=184) (actual time=0.006..0.007 rows=1 loops=31495)
                    Index Cond: (id = "hashtags->PostHashtag"."postId")
                    Filter: ((photo IS NOT NULL) AND (private IS NULL))
                    Rows Removed by Filter: 0
Planning time: 2.865 ms
Execution time: 350.289 ms

如何加快速度?

谢谢

【问题讨论】:

  • 子查询必须有别名。
  • @wildplasser 那里没有子查询。这是一个带括号的连接,不需要别名。

标签: sql postgresql performance sequelize.js


【解决方案1】:

您最好的选择可能是“Post”.“createdAt”上的索引,它可以向后走,根据需要在其他表中查找行,直到它累积 90。然后您还需要“hashtags-> 上的索引” PostHashtag"."postId" 和 hashtags.id.

->  Nested Loop  (cost=18.80..2651.49 rows=7 width=212) (actual time=9.125..336.449 rows=30092 loops=1)

但是,鉴于上述错误估计,可能很难让它使用这种方法。你可以set enable_sort=off 来测试我的首选方法是否可行(如果你有正确的索引应该是可行的),实际上是一种改进。

【讨论】:

  • 我已经有一个"Post"."createdAt" DESC NULLS FIRST 的索引,似乎没有被使用。
  • @Garrett 如果你set enable_sort=off,它会使用它吗?如果是这样,它真的更快吗?
  • 无变化关闭或打开
【解决方案2】:

性能杀手是外部嵌套循环连接,原因是内部嵌套循环连接的错误估计和PostHashtags上的索引扫描。

修复内部嵌套循环添加的偏斜并不容易,但也许它足以改善对索引扫描的估计以倾斜:

ANALYZE "PostHashtags";

如果这修正了错误估计,请调整该表,以便自动分析更频繁地处理它。

要不然试试

SET default_statistics_target = 1000;
ANALYZE "PostHashtags";

看看这是否会改善对索引扫描的估计。

如果这样可以纠正错误估计,

ALTER TABLE "PostHashtags"
 ALTER "hashtagId" SET STATISTICS 1000;

【讨论】:

  • 分析后估计没有变化
  • default_statistics_target = 10000 也没有变化?这确实令人惊讶。
  • 你能解释一下为什么这是一个错误估计吗?我看到-> Bitmap Heap Scan on "PostHashtags" "hashtags->PostHashtag" (cost=17.94..2607.97 rows=711 width=28) (actual time=9.059..79.563 rows=31495 loops=1) 的成本很高,但时间也很长,所以我觉得它很合适。
  • 哦,我应该解释一下的。我说的是行数:估计为 711,实际为 31495。这就是问题的原因。这是一个非常大的表,以至于即使是 10000 的统计分辨率也无法产生更好的估计?
  • 我不确定,仍在阅读这些数据库术语,但我们有大约 1500 万个帖子和 500 万个 PostHashtags。
猜你喜欢
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
  • 2018-12-10
  • 2022-01-12
  • 1970-01-01
  • 2020-12-21
相关资源
最近更新 更多