Cad*_*nge 46 postgresql performance vacuum performance-testing
我试图让 PostgreSQL 积极地自动清空我的数据库。我目前已按如下方式配置自动真空吸尘器:
我注意到自动真空仅在数据库未加载时才会启动,因此我遇到死元组比活元组多得多的情况。有关示例,请参阅随附的屏幕截图。其中一张表有 23 个活动元组,但有 16845 个死元组等待真空。这太疯狂了!

当测试运行完成并且数据库服务器空闲时,自动真空开始,这不是我想要的,因为我希望自动真空在死元组数量超过 20% 活元组 + 50 时启动,因为数据库已经配置。服务器空闲时的自动真空对我来说是无用的,因为生产服务器预计会在持续时间内达到 1000 次更新/秒,这就是为什么即使服务器负载不足我也需要自动真空运行。
有什么我想念的吗?如何在服务器负载较重时强制运行自动吸尘器?
更新
这可能是一个锁定问题吗?有问题的表是通过插入后触发器填充的汇总表。这些表以 SHARE ROW EXCLUSIVE 模式锁定,以防止并发写入同一行。
Jos*_*kus 46
Eelke 几乎肯定是正确的,您的锁定正在阻止 autovacuum。Autovacuum 旨在让位于用户活动,故意。如果这些表被锁定,则 autovacuum 无法清空它们。
然而,对于后人,我想为超强自动真空提供一组示例设置,因为您提供的设置并没有完全做到这一点。请注意,使 autovacuum 更具侵略性不太可能解决您的问题。另请注意,默认 autovacuum 设置基于使用 DBT2 运行 200 多次测试运行以寻求最佳设置组合,因此应假定默认值是好的,除非您有充分的理由不这么想,或者除非您的数据库明显超出OLTP 数据库的主流(例如每秒获得 10K 更新的微型数据库,或 3TB 数据仓库)。
首先,打开日志记录,以便您可以检查 autovacuum 是否正在执行您认为的操作:
log_autovacuum_min_duration = 0
Run Code Online (Sandbox Code Playgroud)
然后让我们让更多的 autovac 工人并让他们更频繁地检查表:
autovacuum_max_workers = 6
autovacuum_naptime = 15s
Run Code Online (Sandbox Code Playgroud)
让我们降低自动真空和自动分析的阈值以更快触发:
autovacuum_vacuum_threshold = 25
autovacuum_vacuum_scale_factor = 0.1
autovacuum_analyze_threshold = 10
autovacuum_analyze_scale_factor = 0.05
Run Code Online (Sandbox Code Playgroud)
然后让我们减少 autovacuum 的可中断性,使其完成得更快,但代价是对并发用户活动产生更大的影响:
autovacuum_vacuum_cost_delay = 10ms
autovacuum_vacuum_cost_limit = 1000
Run Code Online (Sandbox Code Playgroud)
有用于一般激进自动清理的完整程序,这可能适用于获得非常高更新率的小型数据库,但可能对并发用户活动产生太大影响。
另请注意,可以根据table调整 autovacuum 参数,这几乎总是需要调整 autovacuum 行为的更好答案。
不过,它不太可能解决您的真正问题。
小智 38
只是为了查看哪些表完全符合 autovacuum 的条件,可以使用以下查询(基于http://www.postgresql.org/docs/current/static/routine-vacuuming.html)。但是请注意,该查询不会查找特定于表的设置:
SELECT psut.relname,
to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') as last_vacuum,
to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') as last_autovacuum,
to_char(pg_class.reltuples, '9G999G999G999') AS n_tup,
to_char(psut.n_dead_tup, '9G999G999G999') AS dead_tup,
to_char(CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
+ (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
* pg_class.reltuples), '9G999G999G999') AS av_threshold,
CASE
WHEN CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
+ (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
* pg_class.reltuples) < psut.n_dead_tup
THEN '*'
ELSE ''
END AS expect_av
FROM pg_stat_user_tables psut
JOIN pg_class on psut.relid = pg_class.oid
ORDER BY 1;
Run Code Online (Sandbox Code Playgroud)
小智 11
是的,这是一个锁定问题。根据此页面(非完整),VACUUM 需要 SHARE UPDATE EXCLUSIVE 访问,该访问被您正在使用的锁定级别阻止。
你确定你需要这个锁吗?PostgreSQL 符合 ACID,因此并发写入在大多数情况下不是问题,因为如果发生序列化违规,PostgreSQL 将中止其中一个事务。
您也可以通过使用SELECT FOR UPDATE锁定行而不是整个表来锁定行。
另一种没有锁定的替代方法是使用事务隔离级别可序列化。但是,这可能会影响其他事务的性能,您应该为更多的序列化失败做好准备。
小智 8
现有的“qualify for autovacuum”脚本非常有用,但(如正确所述)缺少表特定选项。这是它的修改版本,它考虑了这些选项:
WITH rel_set AS
(
SELECT
oid,
CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)
WHEN '' THEN NULL
ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)::BIGINT
END AS rel_av_vac_threshold,
CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)
WHEN '' THEN NULL
ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)::NUMERIC
END AS rel_av_vac_scale_factor
FROM pg_class
)
SELECT
PSUT.relname,
to_char(PSUT.last_vacuum, 'YYYY-MM-DD HH24:MI') AS last_vacuum,
to_char(PSUT.last_autovacuum, 'YYYY-MM-DD HH24:MI') AS last_autovacuum,
to_char(C.reltuples, '9G999G999G999') AS n_tup,
to_char(PSUT.n_dead_tup, '9G999G999G999') AS dead_tup,
to_char(coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples, '9G999G999G999') AS av_threshold,
CASE
WHEN (coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples) < PSUT.n_dead_tup
THEN '*'
ELSE ''
END AS expect_av
FROM
pg_stat_user_tables PSUT
JOIN pg_class C
ON PSUT.relid = C.oid
JOIN rel_set RS
ON PSUT.relid = RS.oid
ORDER BY C.reltuples DESC;
Run Code Online (Sandbox Code Playgroud)
增加 autovacuum 进程的数量和减少小睡时间可能会有所帮助。这是我在存储备份信息的服务器上使用的 PostgreSQL 9.1 的配置,因此获得了大量插入活动。
http://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html
autovacuum_max_workers = 6 # max number of autovacuum subprocesses
autovacuum_naptime = 10 # time between autovacuum runs
autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for
Run Code Online (Sandbox Code Playgroud)
我也会尝试降低cost_delay使吸尘更具侵略性。
我还可以使用 pgbench 测试自动清理。
http://wiki.postgresql.org/wiki/Pgbenchtesting
高竞争示例:
创建 bench_replication 数据库
pgbench -i -p 5433 bench_replication
Run Code Online (Sandbox Code Playgroud)
运行 pgbench
pgbench -U postgres -p 5432 -c 64 -j 4 -T 600 bench_replication
Run Code Online (Sandbox Code Playgroud)
检查自动清扫状态
psql
>\connect bench_replicaiton
bench_replication=# select schemaname, relname, last_autovacuum from pg_stat_user_tables;
schemaname | relname | last_autovacuum
------------+------------------+-------------------------------
public | pgbench_branches | 2012-07-18 18:15:34.494932+02
public | pgbench_history |
public | pgbench_tellers | 2012-07-18 18:14:06.526437+02
public | pgbench_accounts |
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
45973 次 |
| 最近记录: |