PostgreSQL 18.6 存储运维实战(第 6 篇):DELETE 清空九成数据,磁盘为什么几乎没变

发布时间:2026/11/4 16:09:45

PostgreSQL 18.6 存储运维实战(第 6 篇):DELETE 清空九成数据,磁盘为什么几乎没变 历史表删掉九成数据count(*)已下降磁盘告警却没有解除。普通VACUUM跑完文件仍很大于是团队准备在高峰期执行VACUUM FULL。DELETE、空间可复用、文件缩小是三个不同结果。先判断容量究竟被 heap、索引还是 TOAST 占用再决定要复用、重写还是从数据生命周期上避免逐行删除。先给“空间释放”定义口径同一句“释放了空间”在 PostgreSQL 中可能指四件事口径观察对象DELETE 后普通 VACUUM 后VACUUM FULL 后行对新查询不可见SQL 结果是是是dead tuple 可清理MVCC 版本等待安全 horizon可被清理重写时消失relation 内可复用FSM / 页内空闲不一定通常增加紧凑后剩余较少文件归还文件系统relation 文件尺寸通常否通常否仅可能截尾通常是普通VACUUM的首要工作是回收 dead tuple 占用使空间可被同一 relation 后续复用而不是把每个空洞搬到文件尾。它没有重写整张表因此中间页面的空闲不会自动变成可截掉的连续尾部。三阶段实验行数、内部空间和文件尺寸不是同步变化前提与控制变量在独立测试库运行预留至少数百 MB 空间。测试规模可按机器能力调整但三个阶段必须使用同一张表。不要在生产大表上为了复现实验执行VACUUM FULL。DROPTABLEIFEXISTSevent_log;CREATETABLEevent_log(idbigintPRIMARYKEY,created_at timestamptzNOTNULL,payloadtextNOTNULL);INSERTINTOevent_logSELECTg,timestamptz2026-08-30 00:0008-g*interval1 second,repeat(md5(g::text),8)FROMgenerate_series(1,1000000)ASg;VACUUM(ANALYZE)event_log;统一用下面的查询记录尺寸。pg_table_size包含表主 fork、FSM、VM 和 TOASTpg_indexes_size是索引总量pg_total_relation_size是二者合计。SELECTpg_size_pretty(pg_relation_size(event_log))ASmain_fork,pg_size_pretty(pg_table_size(event_log))AStable_total,pg_size_pretty(pg_indexes_size(event_log))ASindexes_total,pg_size_pretty(pg_total_relation_size(event_log))ASrelation_total;阶段一逐行删除九成数据DELETEFROMevent_logWHEREid900000;SELECTcount(*)FROMevent_log;SELECTpg_size_pretty(pg_relation_size(event_log))ASmain_fork,pg_size_pretty(pg_indexes_size(event_log))ASindexes_total,pg_size_pretty(pg_total_relation_size(event_log))ASrelation_total;预期count(*)只剩十万但 relation 尺寸变化很小。DELETE 写入新 MVCC 状态使旧 tuple 对之后快照不可见它不会逐行把物理文件压紧还会产生 WAL、更新索引清理状态并增加 vacuum 债务。阶段二普通 VACUUMVACUUM(VERBOSE,ANALYZE)event_log;SELECTpg_size_pretty(pg_relation_size(event_log))ASmain_fork,pg_size_pretty(pg_indexes_size(event_log))ASindexes_total,pg_size_pretty(pg_total_relation_size(event_log))ASrelation_total;没有旧快照阻挡时VACUUM 能移除 dead tuple使页面空闲信息进入 Free Space Map。FSM 为 heap 和绝大多数索引记录 relation 内可用空间后续插入可以优先复用这些页面而不必继续扩展文件。文件仍可能不缩小。这不是 VACUUM 失败只有 relation 尾部形成连续空页并且截尾阶段能取得所需锁时普通 VACUUM 才可能把末尾部分归还操作系统。本文删除的是低id物理空洞主要位于旧页面不保证位于文件尾。这一步证明空间能够从“不可复用的 dead tuple”转为“relation 内可复用”仅凭文件尺寸不能证明复用量反过来n_dead_tup降低也不等于文件系统得到容量。阶段三VACUUM FULL先确认当前空闲磁盘、锁窗口、WAL 和副本承受能力再只在测试环境执行VACUUM(FULL,ANALYZE)event_log;SELECTpg_size_pretty(pg_relation_size(event_log))ASmain_fork,pg_size_pretty(pg_indexes_size(event_log))ASindexes_total,pg_size_pretty(pg_total_relation_size(event_log))ASrelation_total;VACUUM FULL把仍存活的内容写入新的紧凑文件通常能显著缩小 relation代价是重写、额外磁盘空间和表级ACCESS EXCLUSIVE锁。它与可以并发读写的普通 VACUUM 不是“强力版”和“普通版”的简单关系而是不同维护操作。实验的实际字节数会因页面布局、元组宽度、版本和文件系统变化。应验证方向不应把某个压缩比当作容量承诺。为什么“删了低 id”与“删了高 id”可能不同如果插入大致按id递增较新的高id更靠近 relation 尾部。删除连续的高id后普通 VACUUM 更有机会截掉尾部空页删除低id则往往留下大量位于文件中间的空洞。但物理位置不是 SQL 契约并发写入、HOT 链、页面复用、fillfactor、聚簇历史都会改变分布。不能根据主键大小直接断言哪些 block 可截断必须用实际尺寸和页面证据验证。普通 VACUUM 的截尾还可能短暂需要更强的锁TRUNCATE false可关闭该行为以避免相关锁影响但也放弃尾部归还。是否调整应基于锁证据和容量目标而不是套用固定参数。先回答空间到底在 heap、索引还是 TOAST总尺寸大不等于 heap 膨胀。排障先拆分 relationSELECTc.oid::regclassASrelation,pg_size_pretty(pg_relation_size(c.oid))ASmain_fork,pg_size_pretty(pg_table_size(c.oid))AStable_with_toast,pg_size_pretty(pg_indexes_size(c.oid))ASindexes,pg_size_pretty(pg_total_relation_size(c.oid))AStotalFROMpg_classAScWHEREc.oidevent_log::regclass;再看统计趋势SELECTn_live_tup,n_dead_tup,n_tup_ins,n_tup_upd,n_tup_del,last_autovacuum,autovacuum_countFROMpg_stat_user_tablesWHERErelidevent_log::regclass;这些是估算或累计统计并非即时精确事实。要判断真实 bloat需结合采样扩展、时间序列和维护窗口不要用n_dead_tup / n_live_tup单一比例直接决定执行重写。索引也需要单独判断。即使 heap 页面可复用索引可能仍有待清理项或结构性空闲反过来索引尺寸大也可能只是业务需要的多组宽索引并非异常膨胀。TOAST 则可能因为大字段版本产生独立体积。长事务会让普通 VACUUM 连“内部复用”都做不到VACUUM 只能移除对所有相关快照都不再需要的 tuple。一个长期持有旧快照的事务可能让已删除行仍必须保留。先做只读检查SELECTpid,usename,application_name,state,xact_start,backend_xmin,wait_event_type,wait_eventFROMpg_stat_activityWHERExact_startISNOTNULLORDERBYxact_start;复制槽的xmin或catalog_xmin也可能保持清理 horizonSELECTslot_name,slot_type,active,xmin,catalog_xmin,restart_lsn,wal_status,safe_wal_sizeFROMpg_replication_slots;发现旧事务或槽后先确认所有者、恢复用途、下游追赶能力与数据保留承诺。直接终止会话或删除复制槽具有业务和恢复风险不属于普通空间排障的默认动作。四条路径不是同一把锤子的不同力度路径主要结果在线代价适用判断DELETE行逻辑不可见产生 dead tuple行锁、WAL、索引与 vacuum 债务零散、需触发器/外键语义的删除DELETE 普通VACUUM清理并让 relation 内空间复用可与读写并发但有 I/O 且受 horizon 限制表会继续以相似规模写入VACUUM FULL重写紧凑文件并归还空间ACCESS EXCLUSIVE、临时空间、WAL/复制压力必须立即回收文件且有维护窗口DROP/DETACH PARTITION整块数据快速退出活动表元数据锁粒度必须提前设计按时间或离散边界整批淘汰如果空闲空间将在未来一周被同表重新写满付出强锁和重写成本把它还给操作系统随后 relation 又扩展回来往往没有业务收益。容量决策应比较“可复用速度”和“再次增长速度”而不是追求最小文件截图。周期淘汰数据分区是在设计删除成本若规则是“只保留 90 天按天整体淘汰”时间范围分区可以把逐行 DML 变成分区生命周期操作CREATETABLEevent_log_p(idbigintNOTNULL,created_at timestamptzNOTNULL,payloadtextNOTNULL)PARTITIONBYRANGE(created_at);CREATETABLEevent_log_p_202608PARTITIONOFevent_log_pFORVALUESFROM(2026-08-01 00:0008)TO(2026-09-01 00:0008);到期时可先摘除而不是立刻销毁ALTERTABLEevent_log_p DETACHPARTITIONevent_log_p_202608 CONCURRENTLY;并发摘除降低父表锁级别但有事务块、默认分区等限制必须按官方语义验证。摘除后先核对保留边界、归档、审计和查询依赖再在另一个受控变更中删除独立表。直接DROP TABLE更快但父表需要ACCESS EXCLUSIVE且误删恢复依赖备份。分区不是事故发生后的无成本补丁。把普通大表迁移为分区表需要新结构、数据搬迁或分批切换唯一约束通常必须包含分区键分区过多还会带来规划和元数据开销。应让分区粒度同时匹配保留周期、查询裁剪和运维批次。生产处置先止住磁盘风险再修生成机制1. 只读确认文件系统剩余容量与增长速度heap、索引、TOAST 各自尺寸dead tuple 生成与清理趋势长事务、复制槽、autovacuum 进度删除的数据是否会被近期写入替代业务是否真的要求立即归还操作系统。2. 最小遏制若磁盘逼近阈值先停止非必要批量写入/删除限制事故继续放大确认备份与副本健康扩容或迁移低风险文件以换取决策时间。不要在剩余空间不足时直接启动需要额外副本空间的重写。3. 根因修复调整 per-table autovacuum 阈值与资源使清理吞吐跟上 dead tuple 生成修复长事务、连接池idle in transaction和失效复制槽治理降低不必要 UPDATE合理设置 fillfactor 提高 HOT 机会将周期淘汰改为匹配保留规则的分区操作仅对确认需要归还文件空间的 relation 选择受控重写。4. 双重验收技术验收包括磁盘水位停止恶化、dead tuple 趋势受控、VACUUM 周期稳定、锁等待和复制延迟在阈值内。业务验收还要确认保留窗口、查询结果、归档可用性与恢复演练通过。VACUUM FULL 的执行护栏必须重写时至少准备可验证的备份或快照以及足以容纳重写与 WAL 峰值的空间明确到单表的目标禁止把数据库级命令当作顺手清理维护窗口与依赖方确认设置合理的lock_timeout避免无限等待后突然抢到锁从较小、低风险 relation 灰度持续观察pg_stat_progress_cluster、磁盘、WAL 和副本达到阻塞会话、复制延迟、磁盘余量或业务错误率阈值时停止后续表。中止重写可以阻止继续扩大影响但已消耗的 I/O、WAL 和缓存扰动不能撤销完成后的新文件也不能靠一条“反向 SQL”恢复原物理布局。回滚的目标应是恢复业务可用性与数据正确性而不是恢复原来的膨胀尺寸。这个实验能证明什么证据能证明不能证明DELETE 后 count 下降新快照看到的业务行减少文件空间已经回收VACUUM 后尺寸不变没有大量尾部文件被截掉VACUUM 没清理任何 dead tuple后续 INSERT 不再增长relation 内空间得到复用所有索引和 TOAST 都无膨胀VACUUM FULL 后文件变小重写能压紧该时刻的存活数据根因已修复、以后不会再涨分区 DROP 很快整分区淘汰避免逐行 DELETE任意删除条件都适合分区面试时怎么讲可以这样回答DELETE 只改变 tuple 的 MVCC 可见性普通 VACUUM 在安全 horizon 后清理 dead tuple并通过 FSM 让空间供 relation 内部复用通常不会移动存活行来缩文件。VACUUM FULL通过 relation rewrite 归还操作系统空间但需要ACCESS EXCLUSIVE锁和额外容量。周期性整批淘汰应在模型阶段按时间分区用 DETACH/DROP 改变删除成本排障时还要先区分 heap、索引、TOAST并处理长事务和 vacuum 吞吐根因。实验清理DROPTABLEIFEXISTSevent_log;DROPTABLEIFEXISTSevent_log_p;删除分区父表会同时删除仍挂载的示例分区只应在确认对象为本实验创建后执行。若分区已经被摘除成为独立表先核对名称和数据归属不要使用CASCADE扩大清理范围。官方资料PostgreSQL 18VACUUMPostgreSQL 18Routine VacuumingPostgreSQL 18Free Space MapPostgreSQL 18Table PartitioningPostgreSQL 18Database Object Size FunctionsPostgreSQL 18Progress ReportingPostgreSQL 18.6 源码标签 REL_18_6
延伸阅读

更多相关文章

2026/11/4 19:16:45

从芯片到系统:MediaTek与NVIDIA合作的系统级设计变革

近两年再看 AI 算力产业链,有一个信号已经非常明显:芯片公司不再只“卖芯片”了。NVIDIA 每一代旗舰硬件发布,主角不再是一颗 GPU,而是一套包含供电、散热、高速互联和管理软件的机柜系统。GDX 与 NVL 系列已经证明,算…

2026/11/4 22:30:40

四足机器人消防应急方案拆解:从热防护到水炮的工程链路

宇树展示四足机器人消防应急解决方案时,大多数人注意到的是一台机器狗被装上水炮、穿烟越障的画面。作为工程师,更需要拆解的是另一层问题:这类方案到底由哪些技术模块组成,进入真实火场之前,哪些环节最容易被演示视频…

2026/11/5 1:39:27

Cadence模块复用实战:从原理图到PCB的高效设计复用方案

这次我们来看一个在 Cadence 设计环境中提升效率的实战方案:模块复用增强。对于硬件工程师和 PCB 设计师来说,面对复杂项目时,重复绘制相同功能的电路模块或反复创建相似的 PCB 布局,是极其耗时且容易出错的过程。一个高效的模块复…

2026/11/5 9:23:26

Jetpack Compose布局:Arrangement与Alignment详解

1. 理解Compose布局中的Arrangement与Alignment 在Jetpack Compose的布局系统中,Arrangement和Alignment是两个核心概念,它们决定了子元素在父容器内的排列方式。虽然名称相似,但它们控制的是布局的不同维度: Arrangement &…

2026/11/5 9:23:26

二叉树构造:前序与中序遍历重建算法解析

1. 二叉树构造问题解析 这道题目是二叉树相关算法中的经典问题,也是各大技术面试中的高频考点。给定一棵二叉树的前序遍历和中序遍历序列,要求我们重建这棵二叉树的结构。在实际工作中,这种序列化和反序列化的能力在处理树形结构数据时非常有…

2026/11/5 9:23:26

Redis缓存三大异常:雪崩、击穿、穿透解析与防御

1. Redis缓存异常现象全景解读 在分布式系统架构中,Redis作为高性能缓存组件承担着流量缓冲的关键角色。但实际生产环境中,缓存层出现的雪崩、击穿、穿透三大异常现象,往往成为系统稳定性的致命威胁。去年双十一大促期间,某电商平…

2026/11/5 9:23:26

物联网数据上报解决方案:AirCloud功能详解与实战

1. 物联网数据上报的痛点与解决方案 作为一名在物联网领域摸爬滚打多年的开发者,我深知数据上报这个看似简单的环节有多让人头疼。记得去年做一个农业大棚监测项目时,光是处理不同型号温湿度传感器的数据兼容问题就耗费了我整整两周时间。更别提网络不稳…

2026/11/5 9:23:26

智能网联汽车安全架构与防护技术解析

1. 联网汽车安全现状与挑战 十年前的车载系统还停留在简单的收音机和CD播放功能,如今的智能网联汽车已经演变成"四个轮子上的数据中心"。根据行业统计,2023年新上市车型中,具备4G/5G联网功能的占比已达78%,平均每辆车搭…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑