database – 为什么postgreSQL会两次检查外键约束?

我有一个带有两个表的
postgresql数据库,一个具有引用另一个的外键约束.约束设置为在更新和删除时级联,因此引用表上的更新应级联到引用表.当我分析引用表的更新时,使用explain analyze我得到了以下输出:

...
Trigger for constraint foreign_key_constraint on referencedtable: time=33.840 calls=1
Trigger for constraint foreign_key_constraint on referencingtable: time=2.394 calls=40
...

我假设第二个触发器被调用40次,因为这是更新值出现在此关系中的次数.

我的问题是为什么需要检查两个表的约束?此外,为什么检查引用表的触发器比引用表花费的时间长得多,因为与引用表触发器(称为40次)相比,它只被调用一次.如果有人能够了解究竟发生了什么,或者为什么需要这么长时间才能得到高度赞赏.

这是架构:

CREATE TABLE课程
(
course_id BIGINT CONSTRAINT course_pk PRIMARY KEY,
标题CHAR(40)
);

CREATE TABLE讲师
(
讲师_id BIGINT CONSTRAINT讲座_pk PRIMARY KEY,
lec_name CHAR(40)
);

CREATE TABLE教授
(
lecturer_id BIGINT CONSTRAINT teaches_lecturer_fk1 REFERENCES讲师(讲师_id),
course_id BIGINT CONSTRAINT teaches_course_fk1 REFERENCES课程(course_id),
desc_teaches CHAR(40),
CONSTRAINT teaches_pk PRIMARY KEY(lecturer_id,course_id)
);

查询和输出:

解释分析UPDATE讲师SET讲师_id = 301 WHERE讲话者= id = 57;

Trigger for constraint teaches_lecturer_fk1 on lecturer: time=33.840 calls=1
Trigger for constraint teaches_lecturer_fk1 on teaches: time=2.394 calls=40

提前致谢.

最佳答案 (通过复制您的示例,使用PostgreSQL 8.4.4,检查pg_trigger和pg_proc表以及最新的源代码来完成.)

触发器运行两次:一次在主要声明中更新讲师;然后再次更新每个教导行以引用讲师中的新值.

约束作为PostgreSQL触发器实现.执行UPDATE语句时,PG识别出讲师更新时有触发器.然后它执行相应的触发函数,PostgreSQL内部函数RI_FKey_cascade_upd.这相当于explain输出中的第一个Trigger事件:

Trigger for constraint teaches_lecturer_fk1 on lecturer: time=33.840 calls=1

执行一些检查后,RI_FKey_cascade_upd为教师生成UPDATE语句,以更新讲师中新值的外键.由于此表上还有一个UPDATE触发器,因此使用内部函数RI_FKey_check_upd.此函数检查新值是否与PK表中的相应行匹配.由于级联更新,FK正在改变每一行调用触发器.这解释了解释输出中的第二个事件:

Trigger for constraint teaches_lecturer_fk1 on teaches: time=2.394 calls=40

据推测,教学中有40行受到级联更新的影响.

我不确定每个触发器的成本来自何处.我一开始认为级联触发器的成本将包含在主要的触发器中,但是在教导中测试10000个受影响的行并不支持这个:

Trigger for constraint teaches_lecturer_fk1 on lecturer: time=540.886 calls=1
Trigger for constraint teaches_lecturer_fk1 on teaches: time=808.930 calls=10000
Total runtime: 1377.017 ms

但是我运行的版本与最新的代码不同,所以也许自8.4.4以来一直有一个优化RI_FKey_cascade_upd的变化.或者,同样可能,我没有正确阅读代码……

点赞