基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

VACUUM 和 VACUUM FULL 有什么本质区别?

知识点图片

在 PostgreSQL 等基于 MVCC(多版本并发控制)的数据库中,VACUUMVACUUM FULL 的本质区别可以用一句话概括:

VACUUM 是“清理房间并腾出空位供以后使用”(逻辑清理),而 VACUUM FULL 是“直接盖一栋更小的新楼并搬过去”(物理重写)。

以下是它们的具体本质区别和详细对比:

1. 空间回收的本质(是否将空间还给操作系统)

  • VACUUM(普通清理):
    • 本质: 扫描表,找到那些被删除或更新后遗留的“死元组”(Dead Tuples),把它们占用的空间标记为“可用”(写入 Free Space Map)。
    • 结果: 表的物理文件大小不会变小。腾出来的空间会留在表文件内部,供未来执行 INSERTUPDATE 时重复使用。(注:只有当死元组刚好位于文件末尾时,普通 VACUUM 才可能会截断文件并归还少量空间)
  • VACUUM FULL(完全清理):
    • 本质: 彻底重写整个表和它的索引。它会读取表中的“活数据”,然后写入到一个全新的物理文件中,最后删除旧文件。
    • 结果: 表的物理文件大小会缩减到最小,省出来的磁盘空间会被真正归还给操作系统

2. 并发控制的本质(是否阻塞业务)

  • VACUUM:
    • 非阻塞: 它使用的是 SHARE UPDATE EXCLUSIVE 锁。这意味着在清理垃圾的同时,允许其他事务对该表进行正常的读写(SELECT, INSERT, UPDATE, DELETE)。
    • 对线上业务影响较小,适合日常自动化维护(AutoVacuum)。
  • VACUUM FULL:
    • 完全阻塞: 它使用的是 ACCESS EXCLUSIVE 锁(排他锁)。在整个执行期间,禁止任何其他事务访问该表(连 SELECT 读操作都不行)。
    • 如果表很大,业务将面临长时间的停机等待。

3. 系统资源消耗的本质

  • VACUUM:
    • 不需要额外的磁盘空间。它只是在现有的文件上进行标记。I/O 开销相对较小。
  • VACUUM FULL:
    • 需要翻倍的磁盘空间: 因为它是把数据写到新文件,所以执行期间,磁盘上会同时存在旧表和新表。如果你的表有 100GB,你的磁盘必须至少还有 100GB 的空闲空间才能执行成功。
    • CPU 和 I/O 开销巨大。

形象的比喻:电影院

假设数据库表是一家电影院,数据是观众。当观众看完电影离开(执行 DELETEUPDATE)后:

  • 普通 VACUUM: 保洁员进去把空座位上的垃圾清理掉,并在登记本上标记这些座位是“空”的。下一批观众买票时,可以直接安排到这些座位上。(电影院的规模/占地面积没有变,电影照常放映)。
  • VACUUM FULL: 把所有还在看电影的观众赶出来,在旁边盖一个座位数刚刚好只够这些观众坐的新电影院,让他们进去接着看,然后把老电影院直接炸掉。(电影院占地面积变小了,但重建期间谁也看不成电影,且需要额外的地皮来盖新电影院)。

核心对比总结表

特性 普通 VACUUM VACUUM FULL
工作方式 标记死元组,记录可用空间 重写整张表和索引到新文件
文件大小 通常不变(内部产生碎片空间) 缩小到极致(消除碎片)
归还空间给OS 否(留给未来的 Insert/Update 用)
是否锁表 否(允许并发读写) 是(完全锁死,拒绝读写)
执行速度 极慢(取决于表大小)
额外磁盘要求 不需要 需要额外一倍的表大小空间
使用场景 日常维护(Autovacuum 自动执行) 灾难/极度膨胀救援(手动执行)

实际工作中的建议:

  1. 千万不要在业务高峰期对大表执行 VACUUM FULL,会导致严重的生产事故(业务卡死)。
  2. 正常情况下,依赖 PostgreSQL 自带的 autovacuum 进程进行普通的 VACUUM 就足够了。
  3. 如果因为大批量删除数据导致表严重膨胀(Bloat),急需收回磁盘空间,又不想锁表,建议使用第三方插件 pg_repackpg_squeeze,它们可以在不阻塞读写的情况下实现类似 VACUUM FULL 的空间回收效果。
00:00
00:00