升级 Postgres 后查询性能下降

Cer*_*rin 4 postgresql statistics upgrade postgresql-12 query-performance

我在 PostgreSQL 12 数据库中有一个包含数百万条记录的表,从 11 升级到 12 后,一些查询开始表现得很糟糕。他们从大约 1 秒缩短到大约 5 分钟。我尝试重建所有索引、清理以及所有常见的 Postgres 容易实现的目标,但性能仍然很糟糕。

这是查询:

SELECT id, activity_count
FROM user
WHERE (search_index) @@ (to_tsquery('pg_catalog.english', '''1234567890'':*') AND active = true
ORDER BY activity_count DESC LIMIT 101
Run Code Online (Sandbox Code Playgroud)

换句话说,找到与给定帐号匹配的所有活跃用户,并从最活跃到最不活跃进行排序。

此查询大约需要 5 分钟才能返回 2 条记录。有什么不对劲。

该列search_index是一个 tsvector,存储表的各个文本字段中的所有关键字(只是帐户编号、名称等)。

我为此列创建了一个 GIN 索引:

CREATE INDEX user_search_index_gin
    ON public.user USING gin
    (search_index)
    TABLESPACE pg_default;
Run Code Online (Sandbox Code Playgroud)

我还有一个该active列的索引:

CREATE INDEX user_active
    ON public.user USING btree
    (active ASC NULLS LAST)
    TABLESPACE pg_default;
Run Code Online (Sandbox Code Playgroud)

我有一个有序索引activity_count

CREATE INDEX user_activity_count
    ON public.user USING btree
    (activity_count ASC NULLS LAST)
    TABLESPACE pg_default;
Run Code Online (Sandbox Code Playgroud)

然而,当我跑步时EXPLAIN,我得到:

"Limit  (cost=0.56..11443.66 rows=101 width=1552)"
"  ->  Index Scan Backward using user_activity_count on user  (cost=0.56..36010185.91 rows=317836 width=1552)"
"        Filter: (active AND (search_index @@ '''1234567890'':*'::tsquery))"
Run Code Online (Sandbox Code Playgroud)

为什么只使用user_activity_count索引而不使用更高效的GIN索引?我该如何解决?

Erw*_*ter 5

使用哪个索引?

虽然您的WHERE条件不是很有选择性,但当前的查询计划对于ORDER BY activity_count DESC LIMIT 101. 看:

然而,你的谓词让我觉得很有选择性:

WHERE (search_index) @@ (to_tsquery('pg_catalog.english', '''1234567890'':*') AND active = true
Run Code Online (Sandbox Code Playgroud)

除非你的例子'1234567890'具有误导性。(您确定要在搜索词中使用单引号吗?)这显然不是您使用的实际查询。不匹配的括号。无论如何,您可能需要“简单”的文本搜索配置(加上一些改进):

WHERE  search_index @@ to_tsquery('pg_catalog.simple', '''1234567890'':*')
AND    active
Run Code Online (Sandbox Code Playgroud)

看:

统计数据

所以看来你的统计数据不是最新的。

从 11 升级到 12 后,一些查询开始表现得很糟糕。他们从大约 1 秒缩短到大约 5 分钟。我尝试重建所有索引、清理以及所有常见的 Postgres 容易实现的目标,但性能仍然很糟糕。

为什么只使用user_activity_count索引而不使用更高效的GIN索引?

您是否也将所有常用的 Postgres 容易实现的目标ANALYZE添加到您的篮子中?你肯定没有提到。考虑手册中的说明

  1. 统计数据

    由于优化器统计信息不会通过 传输pg_upgrade,因此系统将指示您运行命令以在升级结束时重新生成该信息。您可能需要设置连接参数以匹配您的新集群。

如果您的数据库很大vacuumdb,您可能会对这个选项感兴趣--analyze-in-stages。(那艘船可能已经驶向手头的案件。)手册:

此选项对于分析从恢复的转储或pg_upgrade. 该选项将尝试尽快创建一些统计信息,以使数据库可用,然后在后续阶段生成完整的统​​计信息。

有关的: