发布时间:2026/9/3 6:37:30
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/9/3 6:37:30

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

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

2026/9/3 6:37:30

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

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

2026/9/3 6:37:30

MATLAB实现CNN手写数字识别:从MNIST到普通图片数据集全流程

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

2026/9/3 6:42:31

智能问数准确率低?SQLBot数据源导入备注机制是关键

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

2026/9/3 6:42:31

深度学习情感分析实战:从CNN-LSTM混合模型到毕业设计优化

简介:本资源是一套面向高校计算机专业本科生的Python毕业设计/课程设计项目,聚焦电影评论文本的情感极性判别问题,采用Word2Vec词向量与深度学习模型实现正面/负面情感自动分类。资源包共293个文件,涵盖23个核心Python脚本&#x…

2026/9/3 6:42:30

从零实现KNN算法:Matlab实战指南与核心原理深度解析

简介:本资源是面向计算机、电子信息工程及数学等专业本科生的机器学习基础实践材料,聚焦KNN(K近邻)算法原理与Matlab实现,适用于课程设计、期末大作业或毕业设计中的分类任务参考实现。压缩包共4个文件(3个…

2026/9/3 6:42:30

STM32智能小车工程闭环:从芯片选型到PID调参实战

简介:本资源是一套完整的STM32智能小车开发学习套件,面向嵌入式初学者、电子类专业学生及课程设计/毕业设计实践者,解决智能小车项目从硬件搭建、程序编写到功能验证的全流程学习需求。压缩包共248个文件,涵盖53个.h头文件与52个.…

2026/9/3 6:37:30

FreeModbus在STM32F103裸机环境实战部署指南

简介:本资源是一套完整的FreeModbus协议栈在STM32F103平台上的裸机移植工程,面向嵌入式初学者与工业通信开发工程师,解决Modbus RTU从零移植到Cortex-M3芯片的核心技术难点。压缩包共257个文件,含48个C源码(含stm32f10…

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/2 9:00:32

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/2 8:41:06

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/3 0:02:06

零基础装 OpenClaw 小龙虾 AI:Windows 一键部署教程与避坑要点

Windows 部署 OpenClaw 完整教程|本地 AI 智能体 5 分钟落地,环境配置一次搞定 版本说明:Windows 3.1.0 / Mac 2.7.9 写在前面 近两年开源 AI 领域有一款被称作「数字员工」的工具持续走热,它就是 OpenClaw,圈内人更习…

2026/9/3 0:02:06

Hermes Agent 本地部署新方案:Windows 整合包减少依赖报错

Windows 本地部署 Hermes 太麻烦?这版一键包 5 分钟快速跑通 很多人想体验 Hermes Agent,但真正开始部署时,往往会卡在环境配置这一步。 需要安装各类依赖、调试运行环境、处理路径问题,还容易遇到命令行报错、系统拦截、文件缺…

2026/9/3 0:02:06

实测 OpenClaw 一键包,5 分钟完成本地自动化环境搭建

OpenClaw 本地 AI 自动化工具部署指南|使用一键包规避环境配置难题 痛点:部署 AI 自动化工具常常要处理 Python、Node.js 各类依赖,版本冲突、环境配置耗费大量时间,OpenClaw 提供一键安装包,降低部署门槛。 适配系统&…

2026/9/2 1:15:22

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/2 1:15:22

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/2 1:15:20

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…