分区把一张表拆成很多看起来还像一张的片段
声明式分区让 PostgreSQL 对外提供一张逻辑表,同时把行存放在不同分区中。父表负责写入路由,并作为统一查询入口;真正持有数据的是物理分区。它的主要收益往往来自生命周期管理和选择性访问,但选择分区时,也会影响键、查询形态和运维锁,不能只把它看作拆文件。 逻辑父表与物理子表 分区父表本身没有行存储。每个已挂载分区保存符合边界的行,可以有自己的存储参数、索引和维护活动。分区索引也类似,是各物理分区索引的集合,并不是在父表上再保存一整份相同数据。理解这一点,有助于区分统一入口与实际占用磁盘的关系。 范围、列表和哈希分区使用不同划分规则。应根据真实访问和保留要求选择键:按月保存事件可能适合范围分区,其他负载可能需要不同分布。声明式分区本身不会把这些分区自动分散到独立数据库服务器。本地分区仍共享所在数据库的资源和事务环境,不能因为表被拆开,就推断它已经实现分布式分片。 保持父表名字稳定,可以简化应用入口,但不能证明应用代码完全不用改。查询需要暴露适合的分区键限制,才可能从裁剪受益;主键与外键引用也可能需要重新设计。原本按全局唯一标识操作的调用,必须保留同样的身份语义,不能在物理拆分过程中悄悄改变其含义。 分区键不只影响路由 分区表上的唯一或主键约束必须包含全部分区键列,而且这些约束要求分区键不含表达式。各分区的独立索引,不能自行证明其他分区中不存在相同键。因此,day 与 id 的复合主键,并不保证 id 在不同日期之间仍然全局唯一。 从单表全局 id 主键迁移时,这个差别尤其重要。只是把日期加入主键,可能弱化原有身份契约。更改之前,应检查调用方、引用关系和重复防护要求。分区键不是可以完全脱离公开数据模型进行调整的纯物理参数,否则原来按 id 更新一行的操作,可能开始匹配多行。 修改分区键可以把行移动到另一个分区。目标分区必须存在并接受该行,索引和约束仍然生效。这是真实数据变更,不是免费的元数据修改。如果保留策略已经移除了目标范围,迟到的修正可能失败,即使逻辑父表仍然存在。生命周期设计应同时考虑正常新增和历史更正。 坏掉的样子 DETACH 把一张表从分区层级移除,但保留该表及其数据。通过父表查询时不再看到它,脱离后的关系仍可单独检查或导出。DROP 则会连同分区数据一起删除。脱离不等于删除,这两种操作也都不会自动生成已经验证过的归档或备份,不能因为维护命令成功就认定数据已妥善保留。 分区维护需要锁。普通 detach 需要父表上的强锁,可能等待长时间运行的操作,也会影响并发访问。PostgreSQL 提供锁行为不同的并发脱离形式,但有额外限制,例如不能放在显式事务块中执行。应按照实际契约选择操作,不能把“元数据操作”理解为“一定不会阻塞”。 分区过多也会增加规划和内存成本,没有一个普遍适用的行数阈值能证明分区一定划算。应测量有代表性的读取和维护操作,在写入需要前创建未来分区,并明确迟到数据与保留策略如何配合。对于较小且索引合理的表,大量细碎分区可能只增加管理工作,而没有带来足够收益。 快速验证 把下面内容保存为 partition-lifecycle.sql,在可丢弃的 PostgreSQL 18 数据库中执行 psql -X -v ON_ERROR_STOP=1 -f partition-lifecycle.sql。实验使用临时分区和普通事务内 detach,最后回滚移除整个测试环境。 ...