为什么 postgreSQL 在执行 vacuum full table 时等待? 4T table 数据
Why is the postgreSQL waiting while executing vacuum full table? 4T table data
我有一个臃肿的table,它的名字叫"role_info"。
每天大约有20K插入操作和大量更新操作,没有删除操作。
table 现在大约是 4063GB。
我们已经使用dump将table迁移到另一个数据库,而新的table大约有62GB,所以旧数据库上的table膨胀非常严重。
PostgreSQL 版本:9.5.4
table 架构如下:
CREATE TABLE "role_info" (
"roleId" bigint NOT NULL,
"playerId" bigint NOT NULL,
"serverId" int NOT NULL,
"status" int NOT NULL,
"baseData" bytea NOT NULL,
"detailData" bytea NOT NULL,
PRIMARY KEY ("roleId")
);
CREATE INDEX "idx_role_info_serverId_playerId_roleId" ON "role_info" ("serverId", "playerId", "roleId");
字段 'detailData' 的平均大小约为每行 13KB。
下面有SQL个执行结果:
1)
SELECT
relname AS name,
pg_stat_get_live_tuples(c.oid) AS lives,
pg_stat_get_dead_tuples(c.oid) AS deads
FROM pg_class c
ORDER BY deads DESC;
执行结果:
2)
SELECT *,
Pg_size_pretty(total_bytes) AS total,
Pg_size_pretty(index_bytes) AS INDEX,
Pg_size_pretty(toast_bytes) AS toast,
Pg_size_pretty(table_bytes) AS TABLE
FROM (SELECT *,
total_bytes - index_bytes - Coalesce(toast_bytes, 0) AS
table_bytes
FROM (SELECT c.oid,
nspname AS table_schema,
relname AS TABLE_NAME,
c.reltuples AS row_estimate,
Pg_total_relation_size(c.oid) AS total_bytes,
Pg_indexes_size(c.oid) AS index_bytes,
Pg_total_relation_size(reltoastrelid) AS toast_bytes
FROM pg_class c
LEFT JOIN pg_namespace n
ON n.oid = c.relnamespace
WHERE relkind = 'r') a
WHERE table_schema = 'public'
ORDER BY total_bytes DESC) a;
执行结果:
3)
我尝试对 table "role_info" 进行 vacuum full,但它似乎被其他进程阻止,根本没有执行。
select * from pg_stat_activity where query like '%VACUUM%' and query not like '%pg_stat_activity%';
执行结果:
select * from pg_locks;
执行结果:
真空参数有:
我有两个问题:
- 如何应对table腹胀? autovacuum 似乎不起作用。
- 为什么真空完全堵塞了?
根据您的 autovacuum 设置,它每脏 10 页 (200 cost_limit / 20 cost_dirty) 就会休眠 20 毫秒。甚至更多,因为还会有 cost_hit 和 cost_miss。按照这个速度,自动清理 4063GB table 需要超过 12 天的时间,这主要是需要清理页面。那只是节流时间,不包括实际工作时间,也不包括重复扫描索引。所以实际的 运行 时间可能是几个月。 autovacuum 一次完成 运行 而不会被某些事情打断的机会可能非常低。您的数据库是否经常重启?你经常在这个 table 上建立和删除索引,或者添加和删除分区,或者 运行 ALTER TABLE?
请注意,在 v12 中,autovacuum_vacuum_cost_delay 的默认设置降低了 10 倍。这不仅仅是因为对 v12 中的代码进行了一些更改,而是因为我们意识到默认设置是只是对现代硬件不敏感。因此,如果不走得更远,将此更改反向移植到您现有的数据库中可能是有意义的。在 12 之前,你不能降低到小于 1 毫秒,但你可以将它降低到 1 毫秒,也可以增加 autovacuum_vacuum_cost_delay 或降低 vacuum_cost_page_* 设置。
现在这个分析是基于table已经非常臃肿的。为什么 autovacuum 一开始就没有阻止它变得臃肿,回到 table 小到足以在合理的时间内自动清理?这很难说。我们真的没有证据证明当时发生了什么。也许您的设置比现在更受限制(虽然不太可能,因为看起来您只是接受了默认设置),也许它经常被某些东西打断。 pg_stat_all_tables 中 table 的 "autovacuum_count" 和它的 toast table 是什么?
Why did the vacuum full blocked?
因为这就是它的工作原理,as documented。这就是为什么首先要避免陷入这种情况很重要。 VACUUM FULL 需要在最后交换文件节点,并且需要一个 AccessExclusive 锁来做到这一点。它可以先使用较弱的锁,然后尝试升级到 AccessExclusive,但锁升级有很大的死锁风险,因此它会预先使用所需的最强锁。
您需要维护 window,因为没有其他人在使用 table。如果您认为自己已经处于 window 中,那么您应该查看执行阻塞的进程的查询文本。因为已经持有的锁是ShareUpdateExclusive,持有它的不是正常的query/DML,而是某种DDL或维护操作。
如果您现在不能进行维护 window,那么您至少可以在没有 FULL 的情况下进行手动 VACUUM。这需要一个弱得多的锁。它可能不会显着缩小 table,但至少应该释放 space 供内部重用,这样当您确定何时可以安排维护 window 或你接下来的其他步骤是什么。
我有一个臃肿的table,它的名字叫"role_info"。 每天大约有20K插入操作和大量更新操作,没有删除操作。 table 现在大约是 4063GB。 我们已经使用dump将table迁移到另一个数据库,而新的table大约有62GB,所以旧数据库上的table膨胀非常严重。
PostgreSQL 版本:9.5.4
table 架构如下:
CREATE TABLE "role_info" (
"roleId" bigint NOT NULL,
"playerId" bigint NOT NULL,
"serverId" int NOT NULL,
"status" int NOT NULL,
"baseData" bytea NOT NULL,
"detailData" bytea NOT NULL,
PRIMARY KEY ("roleId")
);
CREATE INDEX "idx_role_info_serverId_playerId_roleId" ON "role_info" ("serverId", "playerId", "roleId");
字段 'detailData' 的平均大小约为每行 13KB。
下面有SQL个执行结果:
1)
SELECT
relname AS name,
pg_stat_get_live_tuples(c.oid) AS lives,
pg_stat_get_dead_tuples(c.oid) AS deads
FROM pg_class c
ORDER BY deads DESC;
执行结果:
2)
SELECT *,
Pg_size_pretty(total_bytes) AS total,
Pg_size_pretty(index_bytes) AS INDEX,
Pg_size_pretty(toast_bytes) AS toast,
Pg_size_pretty(table_bytes) AS TABLE
FROM (SELECT *,
total_bytes - index_bytes - Coalesce(toast_bytes, 0) AS
table_bytes
FROM (SELECT c.oid,
nspname AS table_schema,
relname AS TABLE_NAME,
c.reltuples AS row_estimate,
Pg_total_relation_size(c.oid) AS total_bytes,
Pg_indexes_size(c.oid) AS index_bytes,
Pg_total_relation_size(reltoastrelid) AS toast_bytes
FROM pg_class c
LEFT JOIN pg_namespace n
ON n.oid = c.relnamespace
WHERE relkind = 'r') a
WHERE table_schema = 'public'
ORDER BY total_bytes DESC) a;
执行结果:
3)
我尝试对 table "role_info" 进行 vacuum full,但它似乎被其他进程阻止,根本没有执行。
select * from pg_stat_activity where query like '%VACUUM%' and query not like '%pg_stat_activity%';
执行结果:
select * from pg_locks;
执行结果:
真空参数有:
我有两个问题:
- 如何应对table腹胀? autovacuum 似乎不起作用。
- 为什么真空完全堵塞了?
根据您的 autovacuum 设置,它每脏 10 页 (200 cost_limit / 20 cost_dirty) 就会休眠 20 毫秒。甚至更多,因为还会有 cost_hit 和 cost_miss。按照这个速度,自动清理 4063GB table 需要超过 12 天的时间,这主要是需要清理页面。那只是节流时间,不包括实际工作时间,也不包括重复扫描索引。所以实际的 运行 时间可能是几个月。 autovacuum 一次完成 运行 而不会被某些事情打断的机会可能非常低。您的数据库是否经常重启?你经常在这个 table 上建立和删除索引,或者添加和删除分区,或者 运行 ALTER TABLE?
请注意,在 v12 中,autovacuum_vacuum_cost_delay 的默认设置降低了 10 倍。这不仅仅是因为对 v12 中的代码进行了一些更改,而是因为我们意识到默认设置是只是对现代硬件不敏感。因此,如果不走得更远,将此更改反向移植到您现有的数据库中可能是有意义的。在 12 之前,你不能降低到小于 1 毫秒,但你可以将它降低到 1 毫秒,也可以增加 autovacuum_vacuum_cost_delay 或降低 vacuum_cost_page_* 设置。
现在这个分析是基于table已经非常臃肿的。为什么 autovacuum 一开始就没有阻止它变得臃肿,回到 table 小到足以在合理的时间内自动清理?这很难说。我们真的没有证据证明当时发生了什么。也许您的设置比现在更受限制(虽然不太可能,因为看起来您只是接受了默认设置),也许它经常被某些东西打断。 pg_stat_all_tables 中 table 的 "autovacuum_count" 和它的 toast table 是什么?
Why did the vacuum full blocked?
因为这就是它的工作原理,as documented。这就是为什么首先要避免陷入这种情况很重要。 VACUUM FULL 需要在最后交换文件节点,并且需要一个 AccessExclusive 锁来做到这一点。它可以先使用较弱的锁,然后尝试升级到 AccessExclusive,但锁升级有很大的死锁风险,因此它会预先使用所需的最强锁。
您需要维护 window,因为没有其他人在使用 table。如果您认为自己已经处于 window 中,那么您应该查看执行阻塞的进程的查询文本。因为已经持有的锁是ShareUpdateExclusive,持有它的不是正常的query/DML,而是某种DDL或维护操作。
如果您现在不能进行维护 window,那么您至少可以在没有 FULL 的情况下进行手动 VACUUM。这需要一个弱得多的锁。它可能不会显着缩小 table,但至少应该释放 space 供内部重用,这样当您确定何时可以安排维护 window 或你接下来的其他步骤是什么。