У меня есть конвейер обработки, который генерирует два потока данных, затем соединяет два потока данных, чтобы создать третий поток. Каждый поток данных представляет собой серию времени в течение 1 года с 30-минутными интервалами (т.е. 17520 строк). И сгенерированные потоки, и объединенный поток записываются в единую таблицу, снабженную уникальным идентификатором потока и отметкой времени каждой точки в временных рядах.
В абстрактных терминах серии c и g генерируются Функции plpg sql, которые вставляют в таблицу временных рядов данные, хранящиеся в другом месте базы данных (например, с помощью выбора), а затем возвращают уникальные идентификаторы вновь созданной серии. Серия n генерируется с объединением временных рядов, определенных с помощью c_id и g_id с помощью функции calc_n (), которая возвращает идентификатор новой серии n.
Для иллюстрации с использованием некоторого псевдокода:
-- generation transaction
begin;
c_id = select generate_c(p_c);
g_id = select generate_g(p_g);
end transaction;
-- calculation transaction
begin;
n_id = select calculate_n(c_id, g_id);
end transaction;
Я замечаю, что generate_ c () и generate_g () обычно выполняются намного меньше секунды, однако при первом запуске calc_n () это обычно занимает 1 минуту.
Однако если я Запустите метод calc_n () второй раз с теми же параметрами, что и при первом запуске, он выполняется менее чем за секунду (convert_n () генерирует совершенно новый ряд при каждом запуске - он не читает и не перезаписывает никакие данные, рассчитанные при первом выполнении)
Если я остановлю сервер базы данных, перезапустите его, затем запустите Calcu_N ( ) для c_id и g_id, рассчитанных ранее, выполнение функции calc_n () также занимает менее секунды.
Это очень меня смущает. Я мог бы понять, что второй запуск execute_n () занимает всего секунду, если, так или иначе, первый запуск согрел кэш, но если это так, то почему третий запуск (после перезапуска сервера) все еще выполняется быстро, когда любой такой кэш был бы очищен?
Мне кажется, что, возможно, какой-то кэш записи, сгенерированный транзакцией первого поколения, (неожиданно) препятствует первому выполнению Calculate_n (), но после того, как считается, что Calculate_n () завершает, этот кэш очищается, чтобы не мешать последующему выполнению Calculate_n (), когда они происходят. Я посмотрел на активность общего буферного кеша с помощью pg_buffercache, но не увидел каких-либо убедительных доказательств того, что это происходит, хотя, безусловно, были доказательства активности кеша при выполнении execute_n ().
Я могу Быть полностью неосновательным из-за того, что это результат взаимодействия с кешем записи, который был заполнен первой транзакцией, но я пытаюсь понять, почему производительность calc_n () так низка сразу после завершения первой транзакции, но не в других случаях, например сразу после первой попытки или после перезапуска сервера базы данных.
Я использую postgres 11.6.
Чем объясняется такое поведение?
обновление:
Итак, подробнее об этом. Выполнение vacuum analyze
между двумя шагами генерации и шагом вычисления улучшило производительность шага вычисления, но если я обнаружил, что если я повторил шаги снова, мне нужно было запустить vacuum analyze
между шагами генерации и вычислением шаг каждый раз, когда я выполняю последовательность, которая не кажется особенно практичной (поскольку вы не можете вызвать vacuum analyze
в функции или процедуре). Я понимаю необходимость запуска vacuum analyze
хотя бы один раз с разумным количеством строк в таблице. Но мне действительно нужно делать это каждый раз, когда я вставляю еще 34000 строк?