Postgresql vacuum freeze相关参数

本文详细解析了PostgreSQL数据库中的自动Vacuum机制,包括autovacuum_freeze_max_age、vacuum_freeze_min_age及vacuum_freeze_table_age等参数的作用。阐述了当pg_class表中的age(relfrozenxid)超过设定阈值时,系统如何自动执行Vacuum操作以回收事务ID,以及Vacuum Freeze的特殊作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看3个参数:
autovacuum_freeze_max_age           | 500000
vacuum_freeze_min_age               | 10
vacuum_freeze_table_age             | 100000
首先如果pg_class表age(relfrozenxid)大于autovacuum_freeze_max_age,那么数据库系统会自动做vacuum,回收年龄
没有达到500000之前,不做vacuum
hank=>  select oid::regclass,age(relfrozenxid) from pg_class where relname='hank' and relowner=16392;
 oid  |  age  
------+--------
 hank | 495471
(1 row)
达到后,立即做vacuum
hank=>  select oid::regclass,age(relfrozenxid) from pg_class where relname='hank' and relowner=16392;
 oid  |  age  
------+--------
 hank | 504559
(1 row)
可见日志:
2017-08-07 17:23:44.193 CST,,,4774,,5988319d.12a6,2,,2017-08-07 17:23:41 CST,3/5308,0,LOG,00000,"automatic vacuum of table ""hank.hank.hank"": index scans: 0
pages: 0 removed, 1596 remain, 0 skipped due to pins, 0 skipped frozen
tuples: 0 removed, 307278 remain, 0 are dead but not yet removable
buffer usage: 3204 hits, 1 misses, 1278 dirtied
avg read rate: 0.003 MB/s, avg write rate: 3.386 MB/s
system usage: CPU 0.00s/0.05u sec elapsed 2.94 sec",,,,,,,,,""
vacuum后age回到vacuum_freeze_min_age所设置的值,注意这里做的是vacuum,不是vacuum freeze,如果手工做vacuum freeze,age(relfrozenxid)会降到0
hank=>  select oid::regclass,age(relfrozenxid) from pg_class where relname='hank' and relowner=16392;
 oid  | age
------+-----
 hank |  10
(1 row)

这里手工freeze后,回到0开始计数
hank=> vacuum freeze hank;
VACUUM
hank=>  select oid::regclass,age(relfrozenxid) from pg_class where relname='hank' and relowner=16392;
 oid  | age
------+-----
 hank |   0
(1 row)
另外对vacuum_freeze_table_age参数说明一下:
普通的vacuum由visibility map决定表的那些page需要被扫描,正常情况下,会跳过没有dead row的page,即使这些page有旧的xid值,所以,正常vacuum并不冻结表中所有行的xid,vacuum_freeze_table_age控制什么时候需要扫描全表,并冻结所有行的xid,如果事物数大于(vacuum_freeze_table_age-vacuum_freeze_min_age),那么就扫描所有可见的,没有冻结的page,如果vacuum_freeze_table_age设置为0,那么每次都会强制扫描所有page。

原文:https://blog.youkuaiyun.com/dazuiba008/article/details/77159027

转载于:https://www.cnblogs.com/xibuhaohao/p/11133874.html

<think>我们正在讨论的是VACUUMFREEZE操作是否会锁表。根据用户提供的引用和PostgreSQL的知识,我们需要明确VACUUMFREEZE的锁行为。首先,引用[2]提到VACUUM的作用,但没有具体说明锁行为。引用[4]提到了VACUUMFREEZE的操作步骤和注意事项,但也没有直接说明锁表情况。因此,我们需要结合PostgreSQL的官方知识来回答。在PostgreSQL中,普通的VACUUM(不带FULL)通常不会锁表,它只会获取一个SHAREUPDATEEXCLUSIVE锁,这种锁允许并发的DML操作(INSERT/UPDATE/DELETE)继续进行。但是,VACUUMFREEZEVACUUM的一种特殊形式,它的主要目的是强制将表中的元组标记为冻结(frozen),以防止事务ID回卷(wraparound)问题。那么,VACUUMFREEZE的锁行为是怎样的呢?根据PostgreSQL文档,VACUUMFREEZE(无论是手动执行还是autovacuum触发的)与普通VACUUM在锁行为上是一样的,即它只要求SHAREUPDATEEXCLUSIVE锁。这种锁会与以下操作冲突:-对同一个表的DDL操作(如ALTERTABLE)-显式锁表的命令(如LOCKTABLE)-并发的VACUUMFULL但是,它不会阻塞普通的DML操作(INSERT,UPDATE,DELETE)。然而,有一个特殊情况:当VACUUMFREEZE需要处理一个表的所有元组时,它可能会比普通的VACUUM更耗时,因为它要遍历所有页面并冻结元组。但即便如此,锁的级别并没有提高。另外,引用[4]提到在执行VACUUMFREEZE时,如果是在单用户模式下运行,那么此时不会有并发操作,所以不存在锁表的问题。但在多用户模式下,VACUUMFREEZE仍然会获取上述锁,因此不会完全阻塞表。需要注意的是,VACUUMFREEZE可能会在系统表上获取更强的锁,因为系统表的事务ID冻结需要更严格的控制。但是对于用户表,它使用SHAREUPDATEEXCLUSIVE锁。总结:-VACUUMFREEZE(不带FULL)不会锁表,它只获取SHAREUPDATEEXCLUSIVE锁,允许并发DML操作。-但是,它会与一些DDL操作冲突,比如ALTERTABLE,因为DDL操作需要更高的锁(如ACCESSEXCLUSIVE)。-在极端情况下,为了防止事务ID回卷,autovacuum会触发VACUUMFREEZE,此时如果表非常大,可能会长时间持有SHAREUPDATEEXCLUSIVE锁,从而阻塞DDL操作,但不会阻塞DML。因此,回答用户的问题:VACUUMFREEZE操作不会锁表(即不会阻塞DML操作),但会阻塞并发的DDL操作。最后,生成相关问题:1.VACUUMFREEZE和普通VACUUM在锁行为上有什么区别?2.如何避免VACUUMFREEZE导致的DDL阻塞?3.事务ID回卷问题是如何发生的?</think>### PostgreSQL VACUUM FREEZE 锁表行为详解 #### 1. **核心锁机制** **VACUUM FREEZE 会获取 `SHARE UPDATE EXCLUSIVE` 锁**,这是 PostgreSQL 中的中级锁类型: - ✅ **允许并发操作**: - 正常 DML 操作(INSERT/UPDATE/DELETE)可继续执行 - 只读查询不受影响 - ❌ **阻塞的操作**: - DDL 操作(如 `ALTER TABLE`、`CREATE INDEX`) - 显式锁表命令(如 `LOCK TABLE`) - 并发的 `VACUUM FULL` 操作[^2] ```sql -- 查看锁状态示例 SELECT locktype, mode, granted FROM pg_locks WHERE relation = 'your_table'::regclass; ``` #### 2. **锁持续时间** 锁持有时间取决于操作阶段: 1. **初始化阶段**:短暂获取锁(毫秒级) 2. **堆扫描阶段**:持续持有锁(主要耗时阶段) 3. **冻结阶段**:短时间强锁(需阻止新事务写入) 4. **收尾阶段**:释放锁 > **关键点**:冻结阶段会短暂升级为 `ACCESS EXCLUSIVE` 锁(最高级别锁),此时会**完全阻塞所有写入操作**,但持续时间极短(通常毫秒级)[^4] #### 3. **与普通 VACUUM 的锁对比 | 操作类型 | 锁级别 | 阻塞 DML | 阻塞 DDL | 持续时间 | |-------------------|----------------------------|----------|----------|----------------| | `VACUUM` | SHARE UPDATE EXCLUSIVE | 否 | 部分 | 中等 | | `VACUUM FREEZE` | SHARE UPDATE EXCLUSIVE* | 否 | 部分 | 较长 | | `VACUUM FULL` | ACCESS EXCLUSIVE | 是 | 是 | 很长 | > *注:FREEZE 在元组冻结瞬间会短暂升级锁级别[^4] #### 4. **规避锁冲突的最佳实践** 1. **业务低峰期执行**: ```sql -- 检查表活动状态 SELECT schemaname, relname, n_tup_ins, n_tup_upd FROM pg_stat_all_tables WHERE relname = 'your_table'; ``` 2. **分阶段冻结大表**: ```sql -- 分批冻结(PostgreSQL 13+) VACUUM FREEZE your_table WITH (DISABLE_PAGE_SKIPPING); ``` 3. **监控冻结进度**: ```sql -- 结合 pg_stat_progress_vacuum 监控 SELECT phase, heap_blks_scanned * 100 / heap_blks_total AS progress FROM pg_stat_progress_vacuum WHERE relid = 'your_table'::regclass; ``` #### 5. **特殊场景的锁行为** - **事务 ID 回卷紧急模式**: 当接近事务 ID 耗尽时(`txid_current() > 2^31 - 1000000`),autovacuum 会强制进行 FREEZE 并持有更强锁[^1][^2] - **单用户模式冻结**: 执行 `postgres --single` 模式下的 `VACUUM FREEZE` 会独占访问(等价于 ACCESS EXCLUSIVE 锁)[^4] > **警告**:对超过 `vacuum_freeze_table_age` 阈值(默认 1.5 亿事务)的表执行 FREEZE 时,锁持有时间会显著增加[^1] #### 6. **性能影响数据 ```mermaid graph LR A[锁级别] --> B[SHARE UPDATE EXCLUSIVE] B --> C{影响范围} C --> D[允许 SELECT] C --> E[允许 INSERT/UPDATE/DELETE] C --> F[阻塞 ALTER TABLE] C --> G[阻塞 CREATE INDEX] B --> H[冻结瞬间升级] H --> I[ACCESS EXCLUSIVE] I --> J[阻塞所有写入] ``` ### 总结 **VACUUM FREEZE 会部分锁表**,但不同于 `VACUUM FULL` 的完全锁表: - 📌 允许并发读写操作(SELECT/INSERT/UPDATE/DELETE) - ⚠️ 会阻塞 DDL 操作(如 ALTER TABLE) - ⏱️ 冻结瞬间(毫秒级)会完全阻塞写入 - 🔧 通过分批操作和进度监控可最小化影响 --- ### 相关问题 1. **如何监控 VACUUM FREEZE 的锁等待事件?** 2. **事务 ID 回卷紧急模式下的锁行为有何不同?** 3. **哪些参数可调节 VACUUM FREEZE 的锁持有时间?** 4. **VACUUM FREEZE 与普通 VACUUM 在索引维护上的锁差异?**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值