Jul*_*ien 6 postgresql performance statistics autovacuum postgresql-9.6 query-performance
我使用 PostgreSQL 9.6。
我有一个连接 17 个表的查询,其中 9 个有几百万行。查询运行良好,但本周其性能迅速下降。EXPLAIN 的输出没有帮助(所有扫描都是索引扫描,除了非常小的表),我不得不尝试从查询中删除表以隔离导致降级的表。
事实证明,一个包含 40 行的不起眼的表破坏了查询:800 ms 没有该表,而有 30 s。我在桌子上运行了 VACUUM FULL,它运行了大约一秒钟,现在性能恢复正常。
我的问题:
在调试过程中,我对另一台服务器进行了基本备份,因此我有两个文件系统级别的数据库副本,其中一个我没有运行 VACUUM FULL。当我使用 pgAdmin 登录到 unvacuumed 副本时,我收到以下消息:
表“public.clients”上的估计行数与实际行数显着不同。您应该在此表上运行 VACUUM ANALYZE。
unvacuumed 表有 40 行计数和 0 估计。以下是屏幕截图中的其余统计数据。
该表可能很小,但只要 Postgres 预计大约为0行,它就有可能选择与大约40行不同的查询计划- 相同的查询计划效率不高。
由于连接乘以结果行而不是仅仅添加到它们中,因此当连接到像您的示例中那样有几百万行的大表时,小表中的 40 行会产生巨大的影响。这种差异可以很容易地解释执行时间的 30 倍。
或者正如手册所说:
拥有合理准确的统计数据很重要,否则计划的错误选择可能会降低数据库性能。
默认autovacuum
设置适用于大多数安装。考虑:
但是对于包含数百万行的多个表的数据库,我会考虑ANALYZE
不时调整所选表的每个表设置和整个数据库的手册。
一季度。为什么 autovacuum 没有ANALYZE
自动启动?
Q2。为什么VACUUM FULL
解决了问题?
Q2很简单:虽然其他重要的统计数据只更新了ANALYZE
,但 中的基本计数估计pg_class.reltuples
更新得更频繁。手册:
表中的行数。这只是规划器使用的估计值。它由
VACUUM
、ANALYZE
和一些 DDL 命令更新,例如CREATE INDEX
.
Q1更复杂。
再次手册:
守护进程
ANALYZE
严格按照插入或更新的行数进行调度;它不知道这是否会导致有意义的统计变化。
相关设置(除其他外):
autovacuum_analyze_threshold
(integer
)指定触发
ANALYZE
任何一张表中所需的插入、更新或删除元组的最小数量。默认值为50 个 元组。该参数只能在postgresql.conf
文件中或服务器命令行中设置;但是可以通过更改表存储参数来覆盖单个表的设置。
autovacuum_analyze_scale_factor
(floating point
)指定
autovacuum_analyze_threshold
在决定是否触发ANALYZE
. 默认值为0.1(表大小的 10%)。该参数只能在 postgresql.conf 文件或服务器命令行中设置;但是可以通过更改表存储参数来覆盖单个表的设置。
大胆强调我的。
确保测试数据库大部分处于空闲状态以避免测试工件,并且您正在使用默认设置运行:
SELECT * FROM pg_settings WHERE name ~ '^autovacuum|track_counts';
Run Code Online (Sandbox Code Playgroud)
最重要的是:
Run Code Online (Sandbox Code Playgroud)autovacuum_analyze_scale_factor = 0.1 autovacuum_analyze_threshold = 50 autovacuum_naptime = 60 track_counts = on
基本上,autovacuum 每分钟检查一次是否有任何表具有last_estimate / 100 + 50 行更改并ANALYZE
为这些行启动。
要了解您的情况发生了什么:
CREATE TABLE t50 (id int primary key, foo text);
INSERT INTO t50 SELECT g, 'txt' || g FROM generate_series(1,50) g;
SELECT reltuples FROM pg_class WHERE oid = 't50'::regclass;
Run Code Online (Sandbox Code Playgroud)
pg_class.reltuples
是表的估计行数。更多在这里:
你会得到0
。等待 2 分钟以确保我们跨越了 1 分钟的延迟。再检查一遍。还是0
。现在再插入一行并再次检查:
INSERT INTO t50 VALUES (51, 'txt51 triggers analyze');
SELECT reltuples FROM pg_class WHERE oid = 't50'::regclass;
Run Code Online (Sandbox Code Playgroud)
还是0
。再等 2 分钟,再检查一次。多田!我们看到 的更新计数51
。Autovacuum 直到 51 行被插入(或更新或删除)才开始。
要查看更多详细信息(包括 的时间戳last_autoanalyze
):
SELECT * FROM pg_stat_all_tables WHERE relid = 't50'::regclass;
Run Code Online (Sandbox Code Playgroud)
有关的:
运行ANALYZE
在public.clients
手动一次(或整个数据库,它的价格便宜),并为这个重要的表用更积极的每个表的自动清理设置。喜欢:
ALTER TABLE public.clients SET (autovacuum_analyze_scale_factor = 0.01
, autovacuum_analyze_threshold = 10);
Run Code Online (Sandbox Code Playgroud)
由于其他原因,您可能还想审核某些大表的设置。相比:
要加入17桌,这远远超出的默认设置join_collapse_limit
是8。您可能希望使用显式连接语法(也许您已经这样做了)并重写您的查询以将最具选择性的表(或具有最具选择性的谓词)放在SELECT
列表中的首位。有关的:
PS:我想我在运行上面的测试时发现了一个小文档错误。手册上autovacuum_analyze_threshold
写着:
指定触发任意一张表中所需的插入、更新或删除元组的最小数量
ANALYZE
这表明50 个插入 trigger ANALYZE
,而不是像我观察到的51 个。类似pg_settings.short_desc
:
分析之前元组插入、更新或删除的最小数量。
事实上,这里手册中对 autovacuum 的解释符合我的观察:
否则,如果自上次以来废弃的元组数量
VACUUM
超过“真空阈值”,则该表被真空吸尘。
前两句似乎有点不正确。
我提交了一个错误报告。
归档时间: |
|
查看次数: |
857 次 |
最近记录: |