PostgreSQL иногда медленная скорость вставки из-за триггера FK - PullRequest
0 голосов
/ 10 января 2019

У меня есть две таблицы в отношениях мастер-ребенок (несколько детей на мастера).

В одном случае использования мастер со всеми его дочерними элементами должен быть скопирован как новый мастер. Для этого я использую два запроса 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.

...