Почему postgreSQL дважды проверяет ограничения внешнего ключа? - PullRequest
4 голосов
/ 15 сентября 2010

У меня есть база данных postgresql с двумя таблицами, одна из которых имеет ограничение внешнего ключа, которое ссылается на другую.Ограничение установлено каскадно при обновлении и удалении, поэтому обновление ссылочной таблицы должно каскадно соответствовать ссылочной таблице.Когда я проанализировал обновление в ссылочной таблице, используя объяснение и анализ, я получил следующий вывод:

...
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 (course_id BIGINT CONSTRAINT course_pk PRIMARYКЛЮЧ, заголовок CHAR (40));

CREATE TABLE лектор (lecturer_id BIGINT CONSTRAINT lecturer_pk ПЕРВИЧНЫЙ КЛЮЧ, lec_name CHAR (40));

CREATE TABLE учит (лектор _id BIGINT CONSTRECTREFEK Преподает_lecturer_id), course_id BIGINT CONSTRAINT teaches_course_fk1 ССЫЛКИ course (course_id), desc_teaches CHAR (40), CONSTRAINT teaches_pk PRIMARY KEY (lecturer_id, course_id));

Запрос и вывод:

объяснять анализ *

анализироватьSET lecturer_id = 301 ГДЕ lecturer_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

Заранее спасибо.

Ответы [ 3 ]

2 голосов
/ 15 сентября 2010

(Разработано путем воспроизведения вашего примера с использованием 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.Или, скорее всего, я неправильно читаю код ...

0 голосов
/ 15 сентября 2010

Установка внешнего ключа также не устанавливает индекс для быстрой проверки, вы должны сделать это отдельно.Без индекса удаление в главной таблице приведет к сканированию таблицы во внешней таблице.

Также возможно непреднамеренное создание одного и того же ограничения несколько раз, что заставляет postgres выполнять проверку несколько раз.

0 голосов
/ 15 сентября 2010

В каждой строке есть свой чек, 40 обновлений, 40 чеков. Это триггер на основе строки. Вы видите два триггера в двух разных таблицах, которые должны быть из-за разных проверок. Не могли бы вы показать нам схему базы данных, участвующую в вашем обновлении? А также ваш запрос на обновление, который может помочь понять, что происходит в вашей базе данных.

your_database <> my_database

Посмотрите на pg_trigger , он покажет вам FK-триггеры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...