RANGE分区加速UPDATE的根本原因是分区裁剪使数据库跳过无关数据页。当WHERE条件含分区键的等值或范围查询且未被函数包裹时,系统仅扫描目标分区,大幅减少I/O;否则无法裁剪,性能无提升。

为什么 RANGE 分区能加速大表 UPDATE
根本原因不是分区本身快,而是它让 UPDATE 能跳过大量无关数据页。当 WHERE 条件命中分区键(比如 WHERE created_at >= '2024-01-01'),PostgreSQL 或 MySQL 会自动裁剪(prune)掉不满足范围的分区,只扫描目标分区内的数据——物理上少读几十 GB,自然快得多。
但前提是:UPDATE 的 WHERE 必须包含分区键的等值或范围条件,且不能被函数包裹(比如 WHERE DATE(created_at) = '2024-01-01' 就无法裁剪)。
建表时必须显式指定分区键和边界
RANGE 分区不像 HASH 那样“自动分”,你得自己定义每个分区覆盖哪一段值。常见错误是边界写错导致数据写入失败或跨区。
- MySQL 示例:
CREATE TABLE logs (id BIGINT, created_at DATETIME) PARTITION BY RANGE (TO_DAYS(created_at)) (PARTITION p2023 VALUES LESS THAN (TO_DAYS('2024-01-01')), PARTITION p2024 VALUES LESS THAN (TO_DAYS('2025-01-01'))); - PostgreSQL 示例:
CREATE TABLE logs (id BIGINT, created_at DATE) PARTITION BY RANGE (created_at); CREATE TABLE logs_2024 PARTITION OF logs FOR VALUES FROM ('2024-01-01') TO ('2025-01-01'); - 边界必须严格递增、无重叠,且覆盖未来可能写入的数据范围;否则 INSERT 会报
no partition for partitioning key
UPDATE 前务必检查执行计划是否真正裁剪分区
很多人以为加了分区就自动优化,结果 EXPLAIN 一看还是全分区扫描。关键看输出里有没有 Partition Filter(PostgreSQL)或 partitions: p2024(MySQL)。
- 确保 WHERE 中分区键未被隐式转换:比如字段是
DATE类型,就别传'2024-01-01 12:00:00'字符串 - 避免在分区键上用函数:
WHERE YEAR(created_at) = 2024→ 改成WHERE created_at >= '2024-01-01' AND created_at - 复合条件要小心:如果同时有
WHERE created_at > ? AND status = 'pending',而status没建索引,仍可能触发全分区扫描
分区维护比想象中更重,别只顾写入不管清理
旧分区不会自动删除,长期运行后会出现几百个分区,导致查询计划生成变慢、DDL 操作卡顿。DROP 分区虽快,但需手动调度,且不能影响正在执行的 UPDATE。
- MySQL:用
ALTER TABLE logs DROP PARTITION p2022,但注意该分区所有数据立即丢失,不可回滚 - PostgreSQL:先
DETACH PARTITION logs_2022,再DROP TABLE logs_2022,更安全但步骤多 - 切勿在业务高峰期做
REORGANIZE PARTITION或新增分区,这类操作会锁整个父表
最易被忽略的一点:分区键一旦选错(比如用 user_id 而非时间),后续几乎无法通过 UPDATE 语句受益——因为业务更新通常按状态或 ID,而非按用户哈希范围。










