Postgres 数据删除难题破解:DROP TABLE 成唯一可扩展策略!
删除操作的弊端与直觉相反大规模的 DELETE 操作会给数据库增加负担。小规模的单行 DELETE 操作没问题但大规模的批量 DELETE 操作不会立即释放物理磁盘空间还会增加写入和复制开销最终不利于大规模的行清理。当行发生变更时Postgres 可保留同一行的多个版本不同事务能看到查询时的行值这是 Postgres 对“多版本并发控制”MVCC的实现也是其设计核心原则。Postgres 在此做了权衡将修改和删除的行与当前行一起存储依靠事务 ID 和可见性映射跳过“死元组”。删除操作需完全复制仍属于写入操作大规模的 DELETE 操作会影响应用程序的其他写入操作。DELETE 甚至自动清理操作通常不会将数据返还给操作系统只是表示“这些页面中的空间可以被覆盖”。执行 DELETE 操作时索引数据完全不会被触及读取索引的操作必须判断“这个元组是否已死”。总体而言DELETE 实际上是“增加了工作”而不是“完成了工作”。若要对大量数据执行 DELETE 操作会给每个读取查询和自动清理操作增加负担。使用外键和 CASCADE 进行删除操作可能会导致删除一行数据就删除数 GB 的数据从而引发同样的问题。用 DROP 替代 DELETE相比之下DROP TABLE 和 TRUNCATE 需要对表加一个重量级的 AccessExclusiveLock但它们与数据大小基本无关。在物理层面它们直接从操作系统中删除文件并清理 Postgres 缓冲区缓存中与该表相关的页面。在共享缓冲区较大的数据库中这种清理操作可能会比较复杂但它只是元数据清理。DROP TABLE 和 TRUNCATE 的扩展性比 DELETE 好得多。它们不会产生死元组、清理负担也不会给读取操作增加负担会立即为操作系统释放空间。高效的一次性删除操作人们需要删除大量数据的一个常见情况是“由于某个 bug表中充满了垃圾数据”。最近在一个内部可观测性工具中遇到这种情况一个 bug 导致该工具写入了数百万行数据想从数据库中删除这些数据。这些错误的行有一个较早的 updated_at 时间戳任何具有近期时间戳的行都应保留。需要保留的行只有几十万条大部分数据都是垃圾数据。对于这种情况借助 Postgres 的事务性 DDL 进行了如下操作1. BEGIN2. 对相关表显式执行 LOCK TABLE ... IN ACCESS EXCLUSIVE MODE3. 创建一个临时表来保存需要保留的数据4. TRUNCATE big_table;5. INSERT INTO big_table SELECT * FROM temp_keep_big_table;。这种方法一次性处理效果很好写入预写日志WAL的唯一数据是 big_table 中重新插入的行。如果在 TRUNCATE 操作期间对表持有 AccessExclusiveLock 几分钟不可接受可以采用基于触发器的方法。Postgres 扩展 pg_squeeze 大致就是这样操作的用于优化已经存在大量膨胀数据的表。如果需要保留的数据远多于需要删除的数据但需要删除的数据仍然很多典型的做法是在循环中执行多次独立的批量删除操作。使用 Postgres 分区进行持续删除从版本 10 开始Postgres 就提供了强大的分区支持。“父”表可以有“子”表查询可以自动路由到这些子表。Postgres 支持多种分区方案其中非常有用的一种是基于日期的分区。分区可以将“大量 DELETE”的工作负载转变为“偶尔 DROP TABLE”的工作负载。还可以进一步优化按 LIST 对顶级表进行分区然后按 RANGE 对“不可见”子表进行分区以清理旧数据。大胆使用 DROP设计数据库模式和应用程序使大规模 DELETE 操作变为 DROP 或 TRUNCATE可以显著改善数据库性能。在某些情况下它有助于减少读取查询延迟缓解复制延迟峰值总体上提升数据库的健康状况。公司信息[关于我们](/about) [品牌](/brand) [博客](/blog) [更新日志](/changelog) [招聘信息](/careers) [活动信息](/events)产品信息[案例研究](/case-studies) [企业版](/enterprise) [定价](/pricing) [性能基准](/benchmarks)资源信息[文档](/docs) [支持](https://support.planetscale.com/hc/en-us) [服务状态](https://planetscalestatus.com) [信任中心](https://trust.planetscale.com)课程信息[面向开发者的 MySQL](/learn/courses/mysql-for-developers) [数据库扩展](/learn/courses/database-scaling) [学习 Vitess](/learn/courses/vitess)开源项目[Vitess](/vitess) [Vitess 社区](https://vitess.io/slack) [GitHub](https://github.com/planetscale)[隐私政策](/legal/privacy) | [使用条款](/legal/siteterms) | [Cookies 政策](/legal/cookies) | [专利信息](/legal/patents) | [拒绝分享我的个人信息](/legal/privacy#privacy-rights-and-choices)© 2026 PlanetScale, Inc. 保留所有权利。[GitHub](https://github.com/planetscale) | [X](https://twitter.com/planetscale) | [LinkedIn](https://www.linkedin.com/company/planetscale) | [YouTube](https://www.youtube.com/planetscale) | [Discord](https://pscale.link/community) | [Facebook](https://www.facebook.com/planetscaledata)