我有一个带有两个表的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
提前致谢。
答案 0 :(得分:2)
(通过复制你的例子,使用PostgreSQL 8.4.4,检查pg_trigger
和pg_proc
表以及最新的源代码来解决问题。)
触发器运行两次:一次在主语句中更新lecturer
时;然后再次更新每个teaches
行以引用lecturer
中的新值。
约束是作为PostgreSQL触发器实现的。执行UPDATE
语句时,PG会识别UPDATE
lecturer
上的触发器。然后它执行相应的触发器函数PostgreSQL内部函数RI_FKey_cascade_upd
。这相当于解释输出中的第一个Trigger事件:
Trigger for constraint teaches_lecturer_fk1 on lecturer: time=33.840 calls=1
执行一些检查后,RI_FKey_cascade_upd
会为UPDATE
生成teaches
语句,以更新lecturer
中新值的外键。由于此表上还有UPDATE
触发器,因此使用内部函数RI_FKey_check_upd
。此函数检查新值是否与PK表中的相应行匹配。由于级联更新,FK正在改变每一行调用触发器。这解释了解释输出中的第二个事件:
Trigger for constraint teaches_lecturer_fk1 on teaches: time=2.394 calls=40
据推测,teaches
中共有40行受到级联更新。
我不确定每个触发器的成本来自何处。我一开始认为级联触发器的成本将包含在主要成本中,但teaches
中有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
的更改。或者,同样可能,我没有正确阅读代码......
答案 1 :(得分:0)
每行都有自己的支票,40次更新,40次检查。这是一个基于行的触发器。您在两个不同的表中看到两个触发器,这必须是因为不同的检查。您能告诉我们您的更新中涉及的数据库架构吗?还有您的更新查询,这可能有助于了解您的数据库中发生了什么。
your_database<> MY_DATABASE
看看pg_trigger,它会显示FK触发器。
答案 2 :(得分:0)
设置外键不会设置索引以快速进行检查,您必须单独执行此操作。如果没有索引,主表上的删除将导致外表上的表扫描。
此外,可能会无意中多次创建相同的约束,导致postgres多次执行检查。