【问题标题】:Postgres select on large (15m rows) table extremely slow, even with indexPostgres 在大型(15m 行)表上选择非常慢,即使有索引
【发布时间】:2020-10-17 11:36:48
【问题描述】:

我正在尝试运行EXPLAIN ANALYZE,但它根本无法完成,因为它太慢了。如果是,我会发布结果,但现在,这里是EXPLAIN

查询:

EXPLAIN SELECT
    *
FROM
    "Posts" AS "Post"
WHERE
    (
        "Post"."featurePostOnDate" > '2020-06-25 19:28:07.816 +00:00'
        OR (
            "Post"."featurePostOnDate" IS NULL
            AND "Post"."userId" IN (6863684)
        )
    )
AND "Post"."private" IS NULL
ORDER BY
    "Post"."featurePostOnDate" DESC NULLS LAST,
    "Post"."createdAt" DESC NULLS LAST
LIMIT 10;

结果:

Limit  (cost=0.56..110.92 rows=10 width=1136)
  ->  Index Scan using posts_updated_following_feed_idx on "Posts" "Post"  (cost=0.56..284949.60 rows=25819 width=1136)
        Filter: (("featurePostOnDate" > '2020-06-25 19:28:07.816+00'::timestamp with time zone) OR (("featurePostOnDate" IS NULL) AND ("userId" = 6863684)))

索引:

CREATE INDEX  "posts_updated_following_feed_idx" ON "public"."Posts" USING btree (
    "featurePostOnDate" DESC NULLS LAST,
    "createdAt" DESC NULLS LAST
)
WHERE
    private IS NULL;

【问题讨论】:

  • edit您的问题并添加使用explain (analyze, buffers, format text)生成的execution plan 只是一个“简单”解释(就像你已经拥有的那样)
  • @a_horse_with_no_name 仍在等待查询完成,但我认为它正在关闭数据库服务器,因此它可能永远不会完成。如前所述,如果有,我会更新,但如果没有发生,我会寻求任何建议。

标签: postgresql indexing database-performance


【解决方案1】:

所以,由于您有 15m 行,并且您使用了 ANALYZE。使用ANALYZE 实际运行查询,您可以从这里引用它https://www.postgresql.org/docs/9.1/sql-explain.html

WHERE 子句中,您使用了未编入索引的字段

WHERE
    (
        "Post"."featurePostOnDate" > '2020-06-25 19:28:07.816 +00:00'
        OR (
            "Post"."featurePostOnDate" IS NULL
            AND "Post"."userId" IN (6863684)
        )
    )
AND "Post"."private" IS NULL

所以它实际上是在进行顺序扫描以过滤掉行

Filter: (("featurePostOnDate" > '2020-06-25 19:28:07.816+00'::timestamp with time zone) OR (("featurePostOnDate" IS NULL) AND ("userId" = 6863684)))

这可能是您的查询速度慢的原因。

您可能需要在(featurePostOnDate, userId, private)(featurePostOnDate, private) 上使用复合索引。

我希望这会有所帮助。

【讨论】:

  • 构建这些复合索引需要一段时间,但它们都不起作用。它仍然使用 OP 中的索引。
【解决方案2】:

您需要将其编写为两个单独的查询,一个用于 OR 的每个分支。将限制应用于每个查询,然后将它们组合起来并再次联合应用限制。但是如果第一个分支找到 10 行,则第二个分支根本不需要运行,因为所有非 NULL 日期都已排在第一位。

【讨论】:

  • 此时重写查询比添加索引要费力得多,但我担心这种解决方案可能是最好的。我会接受它,因为对于其他读者来说,这是要走的路。
  • 然后UNION结果一起?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
  • 1970-01-01
相关资源
最近更新 更多