Как определить время, необходимое для получения блокировки — и почему — в рамках процедуры

#postgresql #locks

Вопрос:

Я в тупике по поводу возникшей у меня проблемы. Истинный контекст довольно сложен, но я могу свести его к этим функциональным моментам (все остальное не связано с проблемной таблицей).:

  • У меня есть функция запуска, которая содержит несколько SELECT s, а затем UPDATE
  • Выполнение обновления занимает неоправданно много времени («неоправданно» = > 1,4 с)
  • Те же самые точные запросы, выполняемые вне триггера (для одних и тех же строк, параметров и т.д.), Не имеют никаких проблем (т. Е. Они выполняются менее чем за 1-2 мс).
  • Я почти уверен, что индексы и т. Д. Работают по мере необходимости, т. Е. Не должно быть никаких проблем.
  • Нет никаких циклических триггеров
    • В таблице назначения есть триггер on, но даже при его удалении поведение остается прежним.
  • Я провел много тестов безрезультатно, но они довольно значимы:
    • когда обновление заменяется на a SELECT , время отклика, как и ожидалось, быстро
    • когда обновление заменяется на a SELECT... FOR UPDATE , время ответа замедляется, такое же, как и при обновлении
    • ^ это (а также другие вещи) привело меня, возможно, к мысли, что задержка тратится на ожидание достижения блокировки

Никаких других транзакций на самом деле не происходит на этом столе. Я действительно в замешательстве.

Контекст сервера: Это выполняется в AWS/RDS на db.m5.xlarge.

Что я ищу, так это есть ли способ получить некоторую информацию о блокировках, которые происходят в середине транзакции, или, возможно, даже историю приобретенных блокировок? Или что-нибудь еще, что может дать мне представление о том, что вызывает задержку, которая, кажется, так тесно связана с получением блокировки на этом столе.

К сожалению, просто чтобы сделать все еще более разочаровывающим, я не могу воспроизвести проблему, когда я пытаюсь использовать EXPLAIN в теле функции. Единственный способ сделать это (насколько мне известно) — использовать EXECUTE... синтаксис со строкой запроса. У этого нет задержки — это также бесполезно для триггера.

Комментарии:

1. Вы можете установить log_lock_waits, тогда он будет регистрировать любые ожидания блокировки дольше, чем deadlock_timeout (по умолчанию: одна секунда). Если это ничего не показывает, вы можете регистрировать планы ОБЪЯСНЕНИЯ с помощью auto_explain, в частности, используя log_analyze, log_nested_statemets и log_min_duration.

2. @jjanes Это должно быть ответом.

3. @jjanes Спасибо, это именно то, о чем я думал / искал и не мог вспомнить.