TRUNCATE PARTITION 比 DELETE 更快,因其是 DDL 操作,直接释放数据页和元数据,不写事务日志、不触发触发器或外键检查;千万级分区清空仅需毫秒级,而 DELETE 易卡顿并撑爆 undo 表空间。

TRUNCATE PARTITION 为什么比 DELETE 更快
因为 TRUNCATE PARTITION 是 DDL 操作,直接释放数据页和元数据,不走事务日志逐行删除,也不触发触发器或外键检查。在千万级以上分区表中,清空一个分区通常在毫秒级完成;而 DELETE 可能卡住几秒到几分钟,还容易撑爆 undo 表空间。
但注意:MySQL 8.0+ 和 PostgreSQL 12+ 才原生支持该语法,旧版本只能用 DROP PARTITION + REORGANIZE 替代(会重建分区结构,风险更高)。
MySQL 中 TRUNCATE PARTITION 的实际写法
必须确保表是按 RANGE 或 LIST 分区,且目标分区存在。常见错误是传入不存在的分区名,报错:ERROR 1735 (HY000): Unknown partition 'p202301'。
- 先查分区名:
SELECT PARTITION_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'orders' AND TABLE_SCHEMA = 'prod_db'; - 再执行清空:
ALTER TABLE orders TRUNCATE PARTITION p202301; - 支持批量:
ALTER TABLE orders TRUNCATE PARTITION p202301, p202302, p202303; - 不能跨引擎混用——InnoDB 支持,MyISAM 不支持
TRUNCATE PARTITION(只支持全表TRUNCATE)
PostgreSQL 中没有 TRUNCATE PARTITION,得用 TRUNCATE … ONLY
PG 没有 TRUNCATE PARTITION 语法,但可通过继承关系把分区当作独立子表处理。前提是使用原生声明式分区(PARTITION BY RANGE),且子表名由系统生成(如 logs_202301)。
- 确认子表名:
\d+ logs查看分区列表,或查pg_inherits - 清空指定月:
TRUNCATE TABLE ONLY logs_202301;(ONLY关键字不能省,否则会清空父表) - 若用
TRUNCATE TABLE logs_202301(无ONLY),会误删所有继承链上的数据 - PG 14+ 支持
TRUNCATE TABLE logs PARTITION (FOR VALUES FROM ('2023-01-01') TO ('2023-02-01')),但需明确时间范围,不如子表名直觉
自动化脚本里怎么安全地按月清理
别硬编码分区名。真实场景中,分区名常按 pYYYYMM 命名,需动态生成并校验存在性,否则脚本一跑就崩。
- MySQL 示例(存储过程片段):
SET @partition_name = CONCAT('p', DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 12 MONTH), '%Y%m')); SET @sql = CONCAT('ALTER TABLE orders TRUNCATE PARTITION ', @partition_name); SELECT COUNT(*) INTO @exists FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='orders' AND PARTITION_NAME=@partition_name; IF @exists > 0 THEN PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; - 关键点:必须先查
INFORMATION_SCHEMA.PARTITIONS确认分区存在,再拼 SQL;否则PREPARE会直接报错退出 - PG 脚本建议用
psql -c "SELECT ..."先取子表名,再调TRUNCATE TABLE ONLY,避免因命名规则变更导致误删
最易被忽略的是权限——MySQL 需要 ALTER 权限,PG 需要子表上的 TRUNCATE 权限(不是父表权限)。运维配权时常常只给父表,结果脚本静默失败。










