【问题标题】:Why is the postgreSQL waiting while executing vacuum full table? 4T table data为什么 postgreSQL 在执行真空全表时等待? 4T表数据
【发布时间】:2020-03-17 05:47:50
【问题描述】:

我有一个臃肿的表,它的名字是“role_info”。 每天大约有 20K 的插入操作和大量的更新操作,没有删除操作。 该表现在约为 4063GB。 我们已经使用dump将表迁移到另一个数据库,新表大约62GB,所以旧数据库上的表膨胀非常严重。

PostgreSQL 版本:9.5.4

表格架构如下:

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)

我试图对表“role_info”进行真空处理,但它似乎被其他进程阻塞,根本没有执行。

select * from pg_stat_activity where query like '%VACUUM%' and query not like '%pg_stat_activity%';

执行结果:

select * from pg_locks;

执行结果:

真空有参数:

我有两个问题:

  1. 如何处理表膨胀? autovacuum 似乎不起作用。
  2. 为什么真空完全堵塞?

【问题讨论】:

  • 样本数据最好显示为formatted text。请参阅here,了解有关如何创建漂亮表格的一些提示。
  • 您可以检查哪个会话阻止了您的真空:wiki.postgresql.org/wiki/Lock_Monitoring(您可以使用更现代的版本pg_blocking_pids(),但在 Postgres 9.5 中不可用) - 很可能您的会话是“使用该表的事务空闲”

标签: postgresql postgresql-9.5


【解决方案1】:

使用您的 autovacuum 设置,它会在每 10 页(200 cost_limit / 20 cost_dirty)变脏时休眠 20 毫秒。甚至更多,因为也会有 cost_hit 和 cost_miss 。按照这个速度,自动清理一个 4063GB 的表需要超过 12 天的时间,该表主要需要脏页。那只是节流时间,不计算实际工作时间,也不计算索引的重复扫描。所以它的实际运行时间可能是几个月。 autovacuum 一次完成而不会被某事打断的机会可能非常低。您的数据库是否经常重新启动?您是否经常在此表上构建和删除索引,或者添加和删除分区,或者运行 ALTER TABLE?

请注意,在 v12 中,autovacuum_vacuum_cost_delay 的默认设置降低了 10 倍。这不仅仅是因为 v12 中的代码进行了一些更改,而是因为我们意识到默认设置在现代硬件上并不合理.因此,如果不走得更远,将这种更改反向移植到您现有的数据库中可能是有意义的。在 12 之前,您不能低于 1 毫秒,但您可以将其降低到 1 毫秒,同时增加 autovacuum_vacuum_cost_delay 或降低 Vacuum_cost_page_* 设置。

现在这个分析是基于已经非常臃肿的表格。为什么 autovacuum 不首先防止它变得臃肿,当桌子足够小可以在合理的时间内自动清理时?这很难说。我们真的没有证据证明当时发生了什么。也许您的设置比现在更受限制(尽管不太可能,因为您似乎刚刚接受了默认设置),也许它经常被某些东西打断。表及其 toast 表的 pg_stat_all_tables 中的“autovacuum_count”是多少?

为什么真空完全堵塞?

因为它是这样工作的,as documented。这就是为什么首先避免陷入这种情况很重要的原因。 VACUUM FULL 最后需要交换文件节点,并且需要一个 AccessExclusive 锁来做到这一点。可以先使用较弱的锁,然后再尝试升级到 AccessExclusive,但锁升级有很大的死锁风险,因此它需要预先需要的最强锁。

您需要一个没有其他人使用该表的维护时段。如果您认为您已经在这样的窗口中,那么您应该查看执行阻塞的进程的查询文本。因为已经持有的锁是ShareUpdateExclusive,所以持有它的东西不是普通的查询/DML,而是某种DDL或维护操作。

如果您现在不能进行维护窗口,那么您至少可以在没有 FULL 的情况下执行手动 VACUUM。这需要一个更弱的锁。它可能不会显着缩小表格,但至少应该释放空间供内部重用,以便在您确定何时可以安排维护窗口或其他后续步骤时,表格不会变得更大。

【讨论】:

  • 我们没有经常重启我们的数据库,但是现在我们刚刚重启了一次,因为我们试图释放它的空间。这个表上只有一个索引,它只包含两个bigint 字段和一个 int 字段,我们还没有构建或删除它。我们也没有更改表。
  • 感谢您的回复。我刚刚将表架构添加到我的帖子中。
  • vacuum full 进程被autovacuum 进程阻塞,我们通过pg_cancel_backend 取消了autovacuum 进程,然后vacuum full 进程开始运行,wating 状态变为false。真空完整过程大约需要 25 分钟。空间被释放到大约 62GB。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-07
  • 2021-02-25
  • 2018-08-22
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多