PostgreSQL分区表的表空间必须为每个子分区显式指定,父表的TABLESPACE仅影响元数据;ATTACH PARTITION不能修改表空间,需提前创建并设置;索引表空间需单独调整,pg_dump还原时须用--tablespace-mapping映射路径。
CREATE TABLE 时用 PARTITION BY 指定表空间不生效?
postgresql 不支持在 partition by 子句里直接指定表空间,这是常见误解。分区表的主表(父表)本身不存数据,也不分配存储位置;真正控制存储的是每个子分区的 tablespace 设置。
错误做法:CREATE TABLE t (id int) PARTITION BY RANGE (id) TABLESPACE ts1 —— 这里的 TABLESPACE ts1 实际被忽略,仅作用于父表元数据,对后续插入毫无影响。
- 必须为每个
CREATE TABLE ... PARTITION OF显式加TABLESPACE - 父表的
TABLESPACE只影响其系统目录行和默认约束等元数据,不决定数据落盘位置 - 如果漏写,子分区会继承数据库默认表空间,极易导致本该隔离的分区实际混存在同一磁盘上
ALTER TABLE ... ATTACH PARTITION 无法指定表空间?
用 ATTACH PARTITION 方式挂载已有表作为分区时,TABLESPACE 必须在被挂载的表创建时就确定好——它不能在 ATTACH 语句中指定或修改。
典型错误流程:CREATE TABLE p1 (LIKE t); ALTER TABLE p1 SET TABLESPACE ts2; ALTER TABLE t ATTACH PARTITION p1 FOR VALUES FROM (100) TO (200) —— 看似合理,但 ATTACH 不检查、也不迁移物理存储,p1 的数据仍按原表空间存放,只是逻辑上归属分区表。
- 若
p1原来建在默认表空间,即使执行了SET TABLESPACE,也只改变后续新数据的写入位置,已有数据块仍在旧位置 - 真正安全的做法:先用
CREATE TABLE p1 (...) TABLESPACE ts2显式指定,再INSERT INTO p1 SELECT ...导入数据,最后ATTACH -
SET TABLESPACE是 DDL,会锁全表,生产环境批量迁移分区时要考虑阻塞时间
分区切换(DETACH/ATTACH)后索引表空间不一致
分区表的索引默认跟随分区的表空间,但手动 DETACH 后再 ATTACH,如果没重建索引,老索引仍留在原表空间,新分区数据却写入新表空间,造成读写路径分裂。
现象:SELECT spcname FROM pg_tablespace t JOIN pg_class c ON c.reltablespace = t.oid WHERE c.relname = 'p1_idx' 返回的表空间和 p1 本身不一致,查询性能波动、归档备份遗漏都可能由此引发。
- DETACH 后的分区表独立存在,其索引不会自动迁移,也不会自动失效
- ATTACH 前务必确认:目标分区表及其所有索引、序列、TOAST 表均位于期望的表空间
- 推荐操作链:
ALTER INDEX p1_idx SET TABLESPACE ts2→ANALYZE p1→ 再 ATTACH;否则 ANALYZE 可能采样不到真实分布
pg_dump 备份时表空间路径硬编码导致还原失败
使用 pg_dump -Fc 默认不导出表空间定义,但若用了 --no-tablespaces 或显式指定 -T,还原时若目标库没有同名表空间或路径不可写,pg_restore 直接报错 ERROR: tablespace "ts2" does not exist。
这不是权限问题,是还原上下文缺失物理路径映射。尤其跨环境迁移(开发→测试→生产)时,ts2 在源库指向 /data/pg_ts2,而目标库管理员可能建成了 /ssd/pg_ts2,但名字相同、路径不同。
- 生产备份必须带
--no-tablespaces,还原时用pg_restore --tablespace-mapping="ts2=/new/path"显式重定向 - 切勿依赖
CREATE TABLESPACE语句自动执行——dump 文件里的CREATE TABLESPACE是注释掉的,除非加--inserts或--column-inserts - 监控项建议加一条:
SELECT spcname, pg_tablespace_location(oid) FROM pg_tablespace WHERE spcname IN ('ts1','ts2'),部署前比对路径
表空间不是开关,是物理路径绑定。指定错一个分区,整条冷热分离、IO 隔离、故障域划分的设计就断在那个点上。最麻烦的不是设不设,而是设完没验证是否真落到对应磁盘设备上。










