触发器不推荐用于生产环境高频写入表的动态分区,因其按需创建导致新分区未就绪即插入失败、并发建表冲突、子表缺失约束及SQL注入风险,且无法预建索引和统计信息。

触发器能实现动态分区,但不推荐在生产环境直接用它管理高频写入表——它会在每次 INSERT 时执行动态 SQL,阻塞事务、放大锁竞争、且无法预建索引和约束。
为什么触发器方案容易出问题
核心矛盾在于:触发器是「按需创建」,而真实业务需要的是「提前就绪」。常见故障现象包括:
-
ERROR: relation "xxx_202605" does not exist—— 新分区还没来得及建,插入就失败了(尤其高并发场景) - 多个并发
INSERT同时触发建表逻辑,导致CREATE TABLE IF NOT EXISTS冲突或重复执行 - 子表缺失主键、索引、外键或
NOT NULL约束,后续查询或迁移出错 - 触发器函数中用
EXECUTE拼接 SQL,若字段名含特殊字符或注入风险未过滤,会引发语法错误或安全漏洞
auto_insert_into_tbl_partition() 的关键缺陷
这个经典 PL/pgSQL 触发器函数看似通用,但有三个硬伤:
- 它依赖
TG_RELNAME || '_' || curMM命名,但 PostgreSQL 12+ 原生分区表禁止用这种命名方式 attach 分区,必须显式声明PARTITION OF - 它只检查
pg_class.relname,没查pg_inherits,无法识别已 attach 但命名不匹配的子表 - 它没有处理默认分区(
DEFAULT),当插入值不在任何已知分区范围内时,会静默失败或报错
如果非要用触发器,至少做这三件事
仅限低频、测试或遗留系统改造场景。必须补足以下防护:
- 在触发器函数开头加
LOCK TABLE ONLY parent_table IN SHARE UPDATE EXCLUSIVE MODE,避免并发建表冲突 - 子表创建后立即执行
ALTER TABLE ... ATTACH PARTITION ... FOR VALUES FROM (...) TO (...)(RANGE)或FOR VALUES IN (...)(LIST),而非独立建表再继承 - 所有子表必须
LIKE parent_table INCLUDING ALL,并额外手动添加主键(若父表无主键,子表需自行定义,且分区键必须包含在主键中)
真正该用什么替代触发器
触发器只是“能跑”,不是“该用”。2026 年的生产实践共识是:
- 时间类分区(如日志、事件):用
pg_partman.create_parent()配合p_premake和 BGW,自动预建 + 自动清理 - LIST/HASH 分区且值集固定:PostgreSQL 14+ 的
CONFIGURATION语法可一次性声明全部分区,无需触发器 - 应用层强控场景(如按租户 ID 分片):在应用代码里做路由,数据库只负责承载,避免把业务逻辑塞进触发器
最易被忽略的一点:触发器建表后,ANALYZE 不会自动触发,新分区的统计信息为空,首次查询可能走错执行计划——这点连很多 DBA 都会漏掉。

















