У меня есть две таблицы в отношениях мастер-ребенок (несколько детей на мастера).
В одном случае использования мастер со всеми его дочерними элементами должен быть скопирован как новый мастер. Для этого я использую два запроса select + insert - один для создания копий основных записей, а другой для копирования дочерних записей.
Проблема: Запрос на копирование дочерних записей иногда быстрый (50 мс), а иногда очень медленный (1500 мс) , даже с точно таким же состоянием базы данных (я очищаю все таблицы перед каждым тестом) , Я не могу найти никаких шаблонов. Иногда это медленно несколько раз подряд, иногда быстро несколько раз подряд, иногда быстро, медленно, быстро, медленно. Иногда быстро после перезагрузки базы данных, иногда медленно. Я тестирую с одним параллельным клиентом.
Я получил результаты explain analyze
для обоих запросов - вся разница была связана с внешним ключом, соединяющим дочернюю таблицу с главной таблицей:
- Триггер для ограничения fk_attribute_value_element_id: время = 1109.641 вызовов = 1436
против
- Триггер для ограничения fk_attribute_value_element_id: время = 9,779 звонки = 1436
Похоже, что Postgres, проверяя новые дочерние записи, иногда может легко просматривать (недавно вставленные) родительские записи, а иногда нет.
Есть идеи, как отладить это дальше? Как сделать вставки всегда быстрыми?
У меня есть PostgreSQL 9.6.11 в Ubuntu 18.04.
UPDATE:
Вот первый запрос, который копирует мастера (этот запрос всегда быстрый):
insert into element
(id, code, parent_code, hierarchy, version_id, version)
select
nextval('element_seq'),
e.code,
e.parent_code,
e.hierarchy,
:new_version_id,
e.version
from element e
where e.version_id = :old_version_id
Вот второй запрос, который копирует потомков (иногда слишком медленно):
insert into attribute_value
(id, language, value, attribute_description_id, element_id, version)
select
nextval('attribute_value_seq') as id,
old_av.language,
old_av.value,
old_av.attribute_description_id,
new_e.id as element_id,
old_av.version
from element old_e
join element new_e on new_e.version_id = new_version_id and new_e.code = old_e.code
join attribute_value old_av on old_av.element_id = old_e.id
where old_e.version_id = :old_version_id
Вот explain (analyze, buffers)
результаты для второго запроса (влево = медленно, справа = быстро): https://www.diffchecker.com/lBA6sgaf
Медленный FK связан attribute_value.element_id
с element.id
.