ALTER TABLE ... DROP PARTITION 是最快清空分区表历史数据的方式,不走 DML、不写 redo/undo、不触发触发器、不受事务控制,毫秒级物理删除;误用 DELETE FROM ... WHERE partition_col 是常见错误。

直接用 ALTER TABLE ... DROP PARTITION 最快
清空分区表历史数据,DROP PARTITION 是唯一真正“快速”的方式——它不走 DML 流程,不写 redo/undo,不触发触发器,也不受事务控制(MySQL 8.0+ / PostgreSQL 12+ 的 declarative partitioning / Oracle / SQL Server 均支持类似语法)。执行完就物理删除该分区文件或元数据,毫秒级完成。
常见错误是误用 DELETE FROM ... WHERE partition_col :这会扫描全分区、生成大量日志、锁表时间长,且无法释放磁盘空间(尤其在 MySQL InnoDB 中)。
- MySQL 示例:
ALTER TABLE sales DROP PARTITION p_2022_q1, p_2022_q2; - PostgreSQL(声明式分区):
ALTER TABLE sales DETACH PARTITION sales_2022_q1; DROP TABLE sales_2022_q1;(注意 detach + drop 两步不可少) - Oracle:
ALTER TABLE sales DROP PARTITION sales_q1_2022 UPDATE GLOBAL INDEXES;(加UPDATE GLOBAL INDEXES避免全局索引失效)
删之前必须检查分区依赖和索引状态
分区不是孤立的。一旦有全局索引、外键约束、物化视图或正在运行的查询引用该分区,DROP PARTITION 会失败或导致数据不一致。
比如 PostgreSQL 中,若分区上有 FOREIGN KEY 引用,必须先 SET CONSTRAINTS ... DEFERRED 或删掉约束;MySQL 8.0 对二级分区的 DROP 不支持外键自动级联。
- 查依赖:MySQL 查
INFORMATION_SCHEMA.KEY_COLUMN_USAGE;PostgreSQL 查pg_constraint和pg_depend - 查全局索引影响:Oracle 执行前加
UPDATE GLOBAL INDEXES;SQL Server 需确认ONLINE = ON是否可用 - 避免阻塞:确保没有长事务正在扫描该分区(
SHOW PROCESSLIST/pg_stat_activity)
自动清理脚本要防误删,加校验逻辑
线上用定时任务自动删旧分区时,最容易出问题的是日期计算偏差或分区名拼错——比如把 p_202301 写成 p_20231,结果删错分区。
安全做法是:先查出待删分区名列表,人工核对或加白名单校验,再执行。别信“当前时间减 12 个月”这种裸计算。
- MySQL 安全模板:
SELECT partition_name FROM information_schema.partitions WHERE table_schema = 'db' AND table_name = 'sales' AND partition_description < UNIX_TIMESTAMP('2023-01-01'); - PostgreSQL 推荐用
pg_partition_tree()+pg_get_expr(relpartbound, oid)提取边界值,比解析表名可靠 - 所有脚本开头加
SET autocommit = 0;(MySQL)或显式BEGIN; ... ROLLBACK;测试,禁止生产环境直连执行
删完不等于磁盘空间立刻回收
DROP PARTITION 后,操作系统层面的磁盘空间不一定马上可见——InnoDB 表空间不会自动收缩,PostgreSQL 的 DETACH 分区表需手动 VACUUM FULL 主表(仅当主表含行数据),而 Oracle 的 SEGMENT SPACE MANAGEMENT 设置会影响空间重用效率。
- MySQL:若用
innodb_file_per_table=ON,删分区后对应 .ibd 文件被删除,空间立即释放;否则需OPTIMIZE TABLE(但会锁表) - PostgreSQL:
DETACH后原分区表仍存在,必须DROP TABLE才释放空间;主表无数据则无需 vacuum - 验证是否释放:Linux 下用
du -sh /var/lib/mysql/db/sales*或df -h对比前后

















