(Разработано путем воспроизведения вашего примера с использованием 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 строк, которые были подвергнуты каскадному обновлению.
Я не уверен, где расходыдля каждого триггераСначала я подумал, что затраты на каскадный триггер будут включены в основной, но тест с 10000 затронутыми строками в teaches
не поддерживает это:
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
.Или, скорее всего, я неправильно читаю код ...