20 марта 2024

Задержка выполнения запроса в PostgreSQL

Обычно у меня спрашивают: "Как ускорить SQL-запрос?". Но недавно мой коллега сказал: "Для тестов с PostgreSQL мне необходимо замедлить мои запросы". Сразу я решил сам написать функцию, которая будет тормозить его запросы. Но в подобных ситуациях не спешите сразу хвататься за реализацию первой идеи. Всегда помните о богатой, иногда извращенной, фантазии разработчиков PostgreSQL. Оказывается, в PostgreSQL есть функция аналогичная функции Sleep из Win32 API, которая приостанавливает выполнение текущего потока программы на некоторое время.

У PostgreSQL есть три системные функции, которые позволяют приостановить выполнение процесса текущего сеанса переведя его в спящий режим:

  1. pg_sleep (double precision) – приостанавливает выполнение текущего процесса на определенное количество секунд.
  2. pg_sleep_for (interval) – приостанавливает выполнение текущего процесса на определенный интервал времени.
  3. pg_sleep_until (timestamp with time zone) – приостанавливает выполнение текущего процесса до определенного времени.
Функции pg_sleep_for и pg_sleep_until являются синтаксическим сахаром. Они вызывают pg_sleep:
  • pg_sleep_for = pg_sleep(extract(epoch from clock_timestamp() + $1) - extract(epoch from clock_timestamp()))
  • pg_sleep_until = pg_sleep(extract(epoch from $1) - extract(epoch from clock_timestamp()));
Разрешение интервала задержки функции pg_sleep зависит от платформы и обычно равно 0.01 секунды. При ее работе может быть небольшая погрешность, которая зависит от нагрузки на сервер. Но фактическая длительность приостановки выполнения гарантировано не будет меньше указанного интервала времени. По приведенным ниже примерам видно, что время "просыпания" всегда немного больше расчетного.

Пример №1. Вызов функций pg_sleep, pg_sleep_for и pg_sleep_until в запросе.
select CAST(CLOCK_TIMESTAMP() AS TIME) as "Начало", 
       pg_sleep(5) as "pg_sleep(5)", 
       CAST(CLOCK_TIMESTAMP() AS TIME) as "Через 5 секунд";
select CAST(CLOCK_TIMESTAMP() AS TIME) as "Начало", 
       pg_sleep(1.5) as "pg_sleep(1.5)", 
       CAST(CLOCK_TIMESTAMP() AS TIME) as "Через полторы секунды";
select CAST(CLOCK_TIMESTAMP() AS TIME) as "Начало", 
       pg_sleep_for('1 minute 10 second') as "pg_sleep_for('1 minute 10 second')", 
       CAST(CLOCK_TIMESTAMP() AS TIME) as "Через 1 минуту и 10 секунд";
select CAST(CLOCK_TIMESTAMP() AS TIME) as "Начало", 
       pg_sleep_until('today 13:10') as "pg_sleep_until('today 13:10')", 
       CAST(CLOCK_TIMESTAMP() AS TIME) as "Сегодня в 13:10";
Вызов функций pg_sleep, pg_sleep_for и pg_sleep_until в запросе
Пример №2. Вызов функции pg_sleep в PL/pgSQL блоке используя оператор PERFORM.
DO $$
BEGIN
 RAISE INFO 'Начало: %', CAST(CLOCK_TIMESTAMP() AS TIME);
 PERFORM pg_sleep(10); -- задержка на десять секунд
 RAISE INFO 'Конец : %', CAST(CLOCK_TIMESTAMP() AS TIME);
END $$;
Вызов функции pg_sleep в блоке PL/pgSQL

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

Отправить комментарий