English version: README_EN.md
fasttrun — расширение для PostgreSQL 16, PostgreSQL 17 и PostgreSQL 18. Оно ускоряет повторяющийся цикл работы с временными таблицами:
- очистить таблицу;
- заполнить её заново;
- обновить статистику для планировщика;
- выполнить расчёт.
Основные функции расширения:
fasttruncate()очищает локальную временную таблицу;fasttrun_analyze()обновляет оценки планировщика после её заполнения.
Обычные TRUNCATE и ANALYZE уведомляют другие серверные процессы
PostgreSQL об изменениях системного каталога и файлов отношений. При высокой
конкуренции такие уведомления могут создавать заметную нагрузку на CPU.
fasttrun выполняет основную работу только в текущем серверном процессе и в
стандартном режиме не отправляет общих сообщений инвалидации.
Установка расширения сама по себе ничего не ускоряет. Приложение должно явно вызывать функции fasttrun вместо штатных команд в поддерживаемом сценарии.
Быстрые ссылки: проверка перед внедрением, установка, работа через пулер, восстановление после ошибки, обновление.
fasttrun стоит рассматривать, если:
- приложение многократно переиспользует локальные временные таблицы;
- одновременно работают десятки длительно живущих серверных соединений;
- обычные
TRUNCATEиANALYZEсоздают измеримую нагрузку; - приложение можно изменить так, чтобы оно явно вызывало функции fasttrun;
- данные временной таблицы не требуется восстанавливать после
ROLLBACK.
Типичный сценарий — крупные PL/pgSQL-расчёты через пулер соединений. Backend PostgreSQL, то есть серверный процесс одного физического соединения, живёт долго, обслуживает много клиентов и постепенно накапливает временные таблицы для повторного использования.
fasttrun не нужен, если обычные TRUNCATE и ANALYZE не создают заметной
нагрузки. Сначала подтвердите проблему измерениями на своей системе.
Важно: fasttruncate() не является транзакционной заменой TRUNCATE.
После начала физической очистки ROLLBACK не восстановит прежние данные.
Перед использованием проверьте следующее:
-
Целевые таблицы являются самостоятельными локальными временными heap-таблицами, то есть используют стандартный метод хранения PostgreSQL. Это основной поддерживаемый сценарий.
-
Для секционирования и наследования не требуется обход дочерних отношений.
-
Для очистки не нужны внешние ключи,
CASCADE, TRUNCATE-триггеры иRESTART IDENTITY. -
В PostgreSQL включён
track_counts:SHOW track_counts;
Ожидаемое значение —
on. -
После каждого повторного заполнения код вызывает
fasttrun_analyze(). -
Опечатки в именах контролируются приложением: отсутствующая таблица для основных функций считается допустимым случаем и не вызывает ошибку.
-
Для каждого серверного соединения предусмотрен бюджет памяти. По умолчанию кеш статистики fasttrun не ограничен.
-
Для пулера определено, кто очищает временные таблицы перед их использованием следующим клиентом. Само расширение не знает о границах клиентов пулера.
-
У приложения есть возможность вернуться к обычным
TRUNCATEиANALYZE. -
Право
EXECUTEвыдано только доверенным ролям. Функции работают с правами вызывающего пользователя, но не повторяют все проверки владения и ACL, которые выполняют штатныеTRUNCATEиANALYZE.
Не начинайте внедрение с учёта и предварительного создания таблиц. Основные
функции работают без shared_preload_libraries.
Нужны исходные заголовки PostgreSQL и PGXS для той версии сервера, на которую
устанавливается расширение. Используйте pg_config именно этого сервера:
PG_CONFIG=/path/to/postgresql/bin/pg_config
"$PG_CONFIG" --version
make PG_CONFIG="$PG_CONFIG"
make install PG_CONFIG="$PG_CONFIG"make install должен выполняться пользователем, которому разрешена запись в
каталоги библиотек и расширений PostgreSQL.
Для PostgreSQL 16, 17 и 18 нужны отдельные сборки. При последовательной сборке
из одного каталога выполняйте make clean перед сменой PG_CONFIG, иначе
make может повторно использовать объектный файл от другой основной версии.
Установите собранные файлы на все узлы кластера, которые могут обслуживать базу
или стать основным сервером.
Создайте расширение в каждой базе, где оно будет использоваться:
SHOW track_counts;
CREATE EXTENSION fasttrun;
SELECT extversion
FROM pg_extension
WHERE extname = 'fasttrun';Версия по умолчанию — 2.4.0.
Вместо обычного CREATE EXTENSION расширение можно установить в отдельную
схему. Схема с API не должна разрешать недоверенным ролям создавать объекты:
CREATE SCHEMA fasttrun_api;
REVOKE CREATE ON SCHEMA fasttrun_api FROM PUBLIC;
CREATE EXTENSION fasttrun WITH SCHEMA fasttrun_api;При таком варианте квалифицируйте вызовы, например
fasttrun_api.fasttruncate(...). Пример из examples/ жёстко вызывает
public.fasttruncate() и требует отдельной адаптации.
Все последующие SQL-примеры предполагают обычную установку в public. Если вы
выбрали отдельную схему, добавляйте к функциям префикс fasttrun_api. либо
настройте для роли безопасный search_path.
Для fasttruncate(), fasttrun_analyze() и остальных основных функций не
нужны ни рестарт PostgreSQL, ни shared_preload_libraries, ни
session_preload_libraries. Библиотека загрузится при первом вызове функции.
shared_preload_libraries требуется только для общего реестра учёта и
fasttrun_prewarm(). Специального положения fasttrun в списке библиотек нет.
Все 10 SQL-функций после установки имеют стандартное для PostgreSQL право
EXECUTE для PUBLIC и работают как SECURITY INVOKER. Внутренние проверки
владения и ACL таблицы не выполняются. Это особенно важно в transaction
pooling, если один backend работает под разными ролями через SET ROLE.
Настройку прав должен выполнять суперпользователь или владелец функций. При
установке trusted extension (trusted=true) непривилегированная роль владеет
объектом расширения, но созданные C-функции принадлежат начальному
суперпользователю кластера. Для рекомендованной отдельной схемы закройте весь
API, а затем выдайте минимальные права нужным ролям. Повторяйте проверку после
ALTER EXTENSION ... UPDATE, поскольку новая версия может добавить функцию:
REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA fasttrun_api FROM PUBLIC;
GRANT USAGE ON SCHEMA fasttrun_api TO app_role;
GRANT EXECUTE ON FUNCTION fasttrun_api.fasttruncate(text) TO app_role;
GRANT EXECUTE ON FUNCTION fasttrun_api.fasttrun_analyze(text) TO app_role;Ограничьте fasttrun_inspect_stats() отдельно: MCV и гистограммы могут
содержать значения из временных данных.
Для обычной установки в public используйте полный блок:
REVOKE EXECUTE ON FUNCTION public.fasttruncate(text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_analyze(text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_analyze_bulk(text[]) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_relstats(text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_collect_stats(text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_inspect_stats(text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_cache_stats() FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_hot_temp_tables(integer) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_prewarm() FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION public.fasttrun_reset_temp_stats() FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.fasttruncate(text) TO app_role;
GRANT EXECUTE ON FUNCTION public.fasttrun_analyze(text) TO app_role;Остальные права выдайте отдельно ролям приложения, пулера, мониторинга и DBA.
После обновления старой установки проверьте также права у старой функции
fasttruncate_c(text), если она осталась.
trusted=true также позволяет роли с правом CREATE на базу самостоятельно
установить расширение. Реестр учёта общий для всего экземпляра PostgreSQL,
поэтому ACL в одной базе не защищает его от функций, установленных в другой
базе. Если общий учёт включён, контролируйте возможность установки fasttrun во
всех базах экземпляра. Не используйте эту подсистему между недоверенными
арендаторами.
Следующий пример можно выполнить непосредственно в psql:
CREATE TEMP TABLE fasttrun_demo (
id bigint,
category integer
);
INSERT INTO fasttrun_demo
SELECT n, n % 10
FROM generate_series(1, 10000) AS g(n);
SELECT fasttrun_analyze('pg_temp.fasttrun_demo');
SELECT * FROM fasttrun_relstats('pg_temp.fasttrun_demo');
SELECT fasttruncate('pg_temp.fasttrun_demo');
SELECT count(*) = 0 AS table_is_empty
FROM fasttrun_demo;
DROP TABLE fasttrun_demo;Последняя проверка должна вернуть true.
Очищайте таблицу перед началом нового расчёта. Не полагайтесь только на очистку в конце: клиент может завершиться с ошибкой до последнего шага.
Это пример рабочего порядка, а не готовый запрос: замените source_data и
последующий SELECT объектами своего приложения.
BEGIN;
CREATE TEMP TABLE IF NOT EXISTS temp_work (
id bigint,
value numeric
);
-- Удаляем данные, оставшиеся от предыдущего использования backend.
SELECT fasttruncate('pg_temp.temp_work');
INSERT INTO temp_work
SELECT id, amount
FROM source_data
WHERE processing_date = CURRENT_DATE;
-- Обязательно после каждого повторного заполнения.
SELECT fasttrun_analyze('pg_temp.temp_work');
SELECT ...
FROM temp_work
JOIN ...;
COMMIT;ROLLBACK отменит обычные изменения транзакции, но не вернёт данные, которые
уже были удалены успешным fasttruncate().
Внутри PL/pgSQL функции с результатом void вызываются через PERFORM:
DO $plpgsql$
BEGIN
CREATE TEMP TABLE IF NOT EXISTS temp_work (
id bigint,
value numeric
);
PERFORM fasttruncate('pg_temp.temp_work');
INSERT INTO temp_work
SELECT id, amount
FROM source_data
WHERE processing_date = CURRENT_DATE;
PERFORM fasttrun_analyze('pg_temp.temp_work');
-- Дальнейшие запросы к temp_work.
END;
$plpgsql$;PERFORM нельзя выполнять как отдельную команду в psql. В обычном SQL
используйте SELECT fasttruncate(...) и SELECT fasttrun_analyze(...).
Пример более сложной create_temp_table() лежит в
examples/create_temp_table.sql. Это пример
интеграции, а не часть API расширения. Он зависит от pg_variables, схемы
шаблонов и роли _client. В нём текстовые имена подставляются в динамический
SQL без %I, поэтому не передавайте в него недоверенные значения и перед
внедрением в рабочую среду адаптируйте функцию под свой проект.
CREATE TEMP TABLE IF NOT EXISTS не обновляет структуру уже существующей
таблицы. При изменении шаблона после деплоя проверяйте версию структуры и при
необходимости удаляйте и создавайте таблицу заново.
Временная таблица принадлежит физическому серверному процессу PostgreSQL, а не логическому клиенту пулера. Следующий клиент может получить backend, в котором остались таблицы и данные предыдущего клиента.
Соблюдайте следующие правила:
- Очищайте рабочую таблицу в начале каждого расчёта.
- После заполнения всегда вызывайте
fasttrun_analyze(). - В transaction pooling выполняйте весь цикл в одной явной транзакции.
- Statement pooling для такого цикла не подходит.
- Не считайте fasttrun границей безопасности между клиентами. Очистка при передаче backend должна обеспечиваться приложением или настройкой пулера.
- После
SQLSTATE 55000backend нельзя возвращать в пул, пока таблица не восстановлена. Если результат восстановления неочевиден, закройте физическое соединение и позвольте пулеру создать новое. DISCARD TEMPиDISCARD ALLудаляют временные таблицы. Это безопасно, но устраняет выгоду от их повторного использования.
При SQLSTATE 55000 сразу перейдите к разделу
«Восстановление после ошибки».
Учёт и предварительное создание — отдельная необязательная возможность.
fasttrun_prewarm() имеет смысл вызывать при создании нового физического
соединения, а не при каждой выдаче соединения клиенту.
Публичный API содержит 10 SQL-функций.
| Функция | Назначение | Общие сообщения инвалидации |
|---|---|---|
fasttruncate(text) |
Очищает одну локальную временную heap-таблицу, её индексы, TOAST и индексы TOAST | Нет при zero_sinval_truncate=on; при off отправляется служебное сообщение для каждого очищенного отношения |
fasttrun_analyze(text) |
Обновляет локальные оценки размера и при необходимости статистику столбцов | Нет |
fasttrun_analyze_bulk(VARIADIC text[]) |
Последовательно выполняет fasttrun_analyze для массива таблиц |
Нет |
fasttrun_collect_stats(text) |
Явно пересобирает локальную статистику столбцов | Нет |
fasttruncate() берёт AccessExclusiveLock. fasttrun_analyze() и
fasttrun_collect_stats() берут AccessShareLock на время работы.
Открытый курсор или активный запрос к очищаемой таблице приведёт к обычной
SQL-ошибке до изменения файлов.
Для этих функций NULL и отсутствующая таблица означают пустую операцию.
fasttrun_analyze_bulk() также пропускает NULL-элементы массива. Если
найдена обычная таблица, неподдерживаемый метод хранения, секционированный
родитель или родитель наследования, функция завершится ошибкой.
Пакетный вызов не объединяет локальные инвалидации планов. Они выполняются только для отношений, где статистика действительно изменилась. В худшем случае для N таблиц будет N полных проходов по локальному списку планов.
| Функция | Назначение |
|---|---|
fasttrun_relstats(text) |
Возвращает текущие локальные relpages и reltuples |
fasttrun_inspect_stats(text) |
Показывает сохранённые кандидаты статистики в формате pg_statistic |
fasttrun_cache_stats() |
Показывает количество записей и память локальных кешей |
Для отсутствующей таблицы fasttrun_relstats() возвращает NULL, а
fasttrun_inspect_stats() — пустой набор. Пустой набор также означает, что
локальная статистика столбцов ещё не собиралась.
fasttrun_inspect_stats() предназначена для диагностики. Наличие строки в её
результате не гарантирует, что планировщик использует эту статистику прямо
сейчас: проверка свежести может временно скрыть её.
fasttrun_cache_stats() всегда возвращает одну строку со следующими полями:
analyze_entries;column_stats_relid_entries;column_stats_entries;analyze_bytes;column_stats_bytes;total_bytes.
total_bytes равен сумме analyze_bytes и column_stats_bytes. Все значения
относятся только к текущему физическому backend.
| Функция | Назначение |
|---|---|
fasttrun_hot_temp_tables(n) |
Возвращает самые часто встречавшиеся имена временных таблиц |
fasttrun_prewarm() |
Вызывает внешнюю create_temp_table(text) для выбранных имён |
fasttrun_reset_temp_stats() |
Очищает общий реестр и сохранённый файл учёта |
Без shared_preload_libraries первая функция возвращает пустой набор, вторая —
0, а сброс ничего не делает.
fasttrun_analyze() публикует в памяти текущего backend значения, которые
планировщик использует для оценки размера таблицы и индексов.
Внутри одной транзакции повторный вызов обычно вычисляет число строк по
счётчикам изменений и не сканирует таблицу. При COMMIT это дельта-состояние
очищается. Локальные оценки и статистика столбцов сохраняются, но первый вызов
в следующей транзакции может снова просканировать таблицу.
Если таблица не превышает fasttrun.max_analyze_pages, сканирование даёт
точное число строк. Для более крупной таблицы используется ограниченная
выборка блоков и получается оценка, как при обычном ANALYZE.
По умолчанию fasttrun использует тот же механизм анализа обычных столбцов, что и PostgreSQL. Рассчитываются наиболее частые значения (MCV), гистограмма, корреляция, доля NULL, средняя ширина и число различных значений.
Размер выборки по умолчанию — 3000 строк. Это осознанный компромисс между
скоростью и качеством. Обычный ANALYZE часто использует заметно большую
выборку. Для наиболее близкого поведения установите:
BEGIN;
SET LOCAL fasttrun.sample_rows = -1;
SET LOCAL fasttrun.stats_refresh_threshold = 0;
-- Заполнение, fasttrun_analyze() и рабочие запросы.
COMMIT;Даже в этом режиме полное совпадение результатов не гарантируется: случайные
выборки могут различаться. Сбор будет дороже, чем с настройками по умолчанию.
SET LOCAL не оставляет изменённые параметры следующему клиенту пулера.
После небольшого DML кешированная статистика может оставаться видимой, как и
между обычными запусками ANALYZE. При достижении
fasttrun.stats_refresh_threshold она пересобирается, если автоматический сбор
включён, sample_rows не равен нулю и лимит памяти разрешает сбор. В противном
случае fasttrun скрывает устаревшую статистику, чтобы планировщик не использовал
заведомо старое распределение.
track_counts=on требуется для проверки свежести статистики столбцов и
быстрого дельта-пути. При off fasttrun продолжает обновлять размер таблицы
через сканирование или выборку блоков, но не сохраняет и не публикует локальную
статистику столбцов. При попытке собрать статистику непустой таблицы расширение
один раз за время жизни backend пишет WARNING. После включения track_counts снова вызовите
fasttrun_analyze() или fasttrun_collect_stats().
Если сбор не отключён через sample_rows=0 и не остановлен лимитом памяти,
явный fasttrun_collect_stats() запускает полный проход по таблице. Ограничение
fasttrun.max_analyze_pages относится к сканированиям внутри
fasttrun_analyze() и не ограничивает этот явный вызов.
Обычный полный ANALYZE возвращает управление статистикой ядру PostgreSQL для
всей таблицы. ANALYZE table (col1, ...) передаёт ядру только перечисленные
столбцы; локальная статистика остальных столбцов сохраняется. VACUUM без
ANALYZE ничего не меняет. Команды, переписывающие таблицу, скрывают старую
локальную статистику до следующего сбора.
Контекст «пользователь» означает, что параметр можно менять через SET.
Контекст «администратор» означает superuser-контекст или отдельно выданное
право SET ON PARAMETER. Для изменения этих GUC рестарт не нужен.
| Параметр | По умолчанию | Диапазон | Контекст | Назначение |
|---|---|---|---|---|
fasttrun.auto_collect_stats |
on |
boolean | пользователь | Собирать статистику столбцов внутри fasttrun_analyze() |
fasttrun.sample_rows |
3000 |
-1..1000000 |
пользователь | 0 отключает сбор столбцов; при use_typanalyze=on значение -1 использует размер выборки, запрошенный PostgreSQL, а при off — 3000 строк |
fasttrun.stats_refresh_threshold |
0.2 |
0..1 |
пользователь | Доля DML для автоматического пересбора; 0 — при любом DML, 1 — автопересбор отключён |
fasttrun.invalidate_threshold |
0.2 |
0..1 |
пользователь | Допустимое накопленное изменение размера до локального сброса планов |
fasttrun.use_typanalyze |
on |
boolean | пользователь | Использовать ядерные обработчики статистики; off оставляет только базовые показатели |
fasttrun.zero_sinval_truncate |
on |
boolean | пользователь | on очищает файлы без общих сообщений; off использует ядерный путь очистки |
fasttrun.max_analyze_pages |
100000 |
0..2147483647 страниц |
пользователь | Выше порога fasttrun_analyze() переходит к выборке блоков; 0 требует полный скан при необходимости сканирования |
fasttrun.max_stats_memory |
0 |
КБ | пользователь | Мягкий предел памяти статистики столбцов; 0 означает отсутствие предела |
При размере страницы 8 КБ значение max_analyze_pages=100000 соответствует
примерно 800 МБ heap.
Оставляйте fasttrun.zero_sinval_truncate=on в рабочей среде. Значение off
предназначено для диагностики и проверки совместимости. Оно не делает очистку
более безопасной и возвращает общие сообщения инвалидации. Ошибка внутри
ядерного критического участка в этом режиме может привести к PANIC всего
экземпляра PostgreSQL.
max_stats_memory проверяется только перед первым сбором статистики для новой
таблицы. Уже сохранённая статистика продолжает обновляться. Равенство текущего
размера пределу разрешено, поэтому первая новая таблица может превысить лимит
на полный объём статистики всех своих столбцов. Размер этого превышения заранее
не ограничен. В предел входит только column_stats_bytes; память analyze_bytes не
учитывается. Автоматического вытеснения и LRU нет. Если лимит остановил
автоматический сбор, backend выдаёт WARNING один раз. Явный
fasttrun_collect_stats() выдаёт NOTICE при каждой такой попытке.
| Параметр | По умолчанию | Диапазон | Контекст | Назначение |
|---|---|---|---|---|
fasttrun.track_temp_creates |
on |
boolean | администратор | Включает учёт подходящих CREATE TEMP TABLE |
fasttrun.prewarm_count |
1000 |
0..8192 |
пользователь | Максимальное число вызовов вспомогательной функции; 0 отключает prewarm |
fasttrun.prewarm_schema |
dummy_tmp |
имя схемы | администратор | Схема таблиц-шаблонов |
fasttrun.track_schedule |
mon-fri 08:00-18:00 |
строка | администратор | Временные окна, когда учитываются попытки создания таблиц |
Эти параметры имеют практический смысл только при загрузке fasttrun через
shared_preload_libraries.
Кеши статистики принадлежат физическому backend и не разделяются между
соединениями. При 300 таблицах по 300 столбцов объём может составлять десятки
или сотни мегабайт на backend. Широкие значения и увеличенный
default_statistics_target повышают расход.
Для измерения используйте фактические данные:
SELECT pg_backend_pid(), *
FROM fasttrun_cache_stats();Запрос показывает только backend, на котором он выполнен. В transaction pooling разные вызовы могут попасть на разные серверные соединения.
Периодический ресайкл соединений освобождает локальные кеши. Для предсказуемой
деградации можно задать fasttrun.max_stats_memory. После достижения лимита
новые таблицы продолжат получать оценки размера, но останутся без локальной
статистики столбцов. Уже принятая статистика не вытесняется.
Развернуть необязательный раздел
Этот раздел необязателен. Он нужен только для длительно живущих пулов, где заранее создавать небольшой набор часто используемых временных таблиц выгоднее, чем создавать все возможные таблицы.
Добавьте fasttrun в shared_preload_libraries и перезапустите PostgreSQL:
shared_preload_libraries = 'fasttrun'Если в списке уже есть другие расширения, сохраните их. Специального требования ставить fasttrun последним нет.
session_preload_libraries не заменяет shared_preload_libraries: оно не
создаёт общий реестр учёта.
Учитываются только попытки команд вида:
CREATE TEMP TABLE temp_work
(LIKE dummy_tmp.temp_work INCLUDING ALL);Имя схемы в LIKE должно явно совпадать с fasttrun.prewarm_schema.
Создание временной таблицы без такого LIKE не учитывается. INCLUDING ALL
показан только для примера и не является обязательным условием учёта.
Также не учитываются CREATE TEMP TABLE AS, SELECT INTO TEMP, определения
столбцов без LIKE, неквалифицированный LIKE template и шаблоны из другой
схемы. Для последующего предварительного создания имя временной таблицы должно
совпадать с именем шаблона. Сам реестр это равенство не проверяет: попытка
CREATE TEMP TABLE foo (LIKE dummy_tmp.bar) запишет имя foo, но при
предварительном создании будет искаться dummy_tmp.foo.
Счётчик обновляется до выполнения CREATE. Поэтому он отражает попытки, а не
только успешно созданные таблицы. Его увеличивают также неуспешные команды,
CREATE ... IF NOT EXISTS без фактического создания и команды, которые позже
были отменены транзакцией.
Реестр:
- общий для всего экземпляра PostgreSQL;
- содержит не более 8192 имён;
- использует только имя таблицы, без OID базы, схемы и пользователя;
- суммирует одинаковые имена из разных баз;
- после заполнения молча не принимает новые имена.
Реестр не является источником аудита или безопасности. Сессия, способная
отправлять подходящие команды CREATE TEMP TABLE, может увеличить счётчики
даже неуспешными попытками и заполнить реестр новыми именами. Используйте эту
возможность только для доверенной нагрузки и контролируйте заполнение.
fasttrun_reset_temp_stats() очищает весь общий реестр, а не только данные
текущей базы.
fasttrun_hot_temp_tables(0) возвращает все записи. Сортировка выполняется по
числу попыток, затем по времени последней попытки и имени.
По умолчанию попытки учитываются по рабочим дням с 08:00 до 18:00:
fasttrun.track_schedule = 'mon-fri 08:00-18:00'Пустая строка включает учёт постоянно. Поддерживается до восьми окон:
fasttrun.track_schedule = 'mon-fri 08:00-18:00; sat 10:00-14:00'Дни задаются как mon, tue, wed, thu, fri, sat, sun. Время
окончания не входит в окно. Значение 24:00 допустимо только как время
окончания. Окно через полночь нужно разделить:
fasttrun.track_schedule = 'fri 22:00-24:00; sat 00:00-02:00'Используется log_timezone сервера. Ошибка формата записывается как WARNING,
после чего учёт остаётся постоянно включённым.
fasttrun_prewarm() работает в текущей базе и текущем соединении с правами
вызывающей роли. Он выбирает до fasttrun.prewarm_count имён. fasttrun проверяет
только наличие любого отношения с таким именем в fasttrun.prewarm_schema.
Если отношения нет, имя пропускается. Проверить, что это действительно
подходящий шаблон, должна пользовательская create_temp_table(). Функция не
дополняет результат менее популярными именами вместо пропущенных.
Расширение не устанавливает create_temp_table(text). Оно выполняет
неквалифицированный вызов:
SELECT create_temp_table($1);Функция с совместимой сигнатурой должна быть доступна через текущий
search_path. Размещайте её в доверенной схеме и не допускайте, чтобы раньше
неё в search_path находились схемы, куда обычные пользователи могут создавать
функции.
Возвращаемое число — количество выполненных вызовов create_temp_table(), а
не обязательно количество новых таблиц. Создание отсутствующей таблицы идёт
через обычный DDL и создаёт стандартные каталожные инвалидации. Поведение для
уже существующей таблицы полностью определяется пользовательской
вспомогательной функцией.
Одна ошибка create_temp_table() прерывает весь fasttrun_prewarm(). Ранее
обработанные таблицы уже могли быть физически очищены пользовательской функцией,
и ROLLBACK не обязан вернуть их данные.
Перед первым включением задайте небольшое fasttrun.prewarm_count, измерьте
время и число создаваемых таблиц, затем увеличивайте значение. Значение по
умолчанию 1000 не является рекомендацией для любой системы.
Пример:
SELECT * FROM fasttrun_hot_temp_tables(20);
SELECT fasttrun_prewarm();При штатной остановке PostgreSQL реестр атомарно сохраняется в
$PGDATA/pg_stat/fasttrun_temp_stats и загружается при следующем старте.
При аварийном завершении актуальное состояние не записывается. Может быть загружена более старая успешно сохранённая копия. Ошибки записи фиксируются в журнале PostgreSQL; недописанный временный файл удаляется.
Файл не пишется в WAL, не реплицируется и не входит в pg_dump.
fasttrun_reset_temp_stats() очищает реестр и удаляет файл немедленно;
ROLLBACK этот сброс не отменяет.
Если ошибка произошла до начала физической очистки, PostgreSQL откатывает операцию обычным способом и прежние данные остаются целы.
Если ошибка возникла после начала очистки, прежние файлы уже нельзя безопасно
восстановить. fasttrun блокирует таблицу в текущем backend. SELECT, DML,
COPY, планирование и функции расширения для неё возвращают
SQLSTATE 55000. Обычный ROLLBACK и откат к точке сохранения блокировку не
снимают.
Сначала завершите ошибочную транзакцию:
ROLLBACK;Затем выберите один способ восстановления:
- Повторите
fasttruncate(). После успешного вызова таблица снова доступна, пуста и должна быть заполнена заново. - Удалите таблицу и создайте её заново.
- Выполните
DISCARD TEMPилиDISCARD ALLвне транзакции. Это удалит все временные таблицы текущего backend. - Закройте физическое соединение. Для backend под управлением пулера это самый простой безопасный вариант.
Пример повторной очистки:
BEGIN;
SELECT fasttruncate('pg_temp.temp_work');
COMMIT;DISCARD ALL дополнительно сбрасывает подготовленные планы, параметры сессии и
другое состояние соединения. Если нужно удалить только временные таблицы,
используйте DISCARD TEMP.
Для новых операций приложение можно временно вернуть к штатным командам:
TRUNCATE pg_temp.temp_work;
ANALYZE pg_temp.temp_work;Это не восстанавливает уже заблокированную fasttrun таблицу. Для неё используйте один из четырёх способов выше.
При fasttrun.zero_sinval_truncate=off расширение вызывает ядерный
RelationTruncate для каждого отношения. Ошибка в критическом участке
физической очистки PostgreSQL приводит к PANIC. Это завершает все серверные
сеансы данного экземпляра, а не только текущий backend. При
restart_after_crash=on postmaster заново запускает процессы и выполняет
аварийное восстановление. Пулер увидит массовый обрыв соединений.
При restart_after_crash=off PostgreSQL не запускает процессы автоматически;
перезапуск и восстановление должен выполнить оператор или система управления
кластером.
Проверьте журнал и состояние всего экземпляра PostgreSQL. Продолжать работу старых соединений после такого события невозможно.
Поддерживается обновление с версий 2.0, 2.1, 2.1.1, 2.1.2, 2.2.0,
2.3.0, 2.3.1, 2.3.2, 2.3.3 и 2.3.4.
Обновление C-библиотеки планируйте как обслуживание серверных процессов. Новая сборка и SQL-файлы должны быть установлены на всех узлах кластера.
- Если fasttrun загружен через
shared_preload_libraries, остановите PostgreSQL, установите новую сборку и снова запустите сервер. - При ленивой загрузке или
session_preload_librariesостановите приём нового трафика и закройте все backend, которые могли загрузить старую библиотеку. Для пулера это означает полный ресайкл серверных соединений. После этого установите новую сборку.
Команды установки:
make PG_CONFIG=/path/to/pg_config
make install PG_CONFIG=/path/to/pg_configПосле запуска или открытия нового соединения выполните в каждой базе от имени владельца расширения или суперпользователя:
ALTER EXTENSION fasttrun UPDATE TO '2.4.0';При физической репликации установите файлы и на резервные узлы, но выполняйте
ALTER EXTENSION только на доступном для записи основном сервере. Изменения
системного каталога попадут на реплики через обычную репликацию.
Это важно для обновления 2.3.4 → 2.4.0: SQL-миграция добавляет функцию, которой нет в старой C-библиотеке.
При переходе на новую основную версию через pg_upgrade заранее соберите и
установите fasttrun против нового pg_config. Каталог расширений переносится
вместе с базой; повторный CREATE EXTENSION не требуется. Файл общего реестра
учёта не является частью каталога расширения и должен считаться восстанавливаемым
служебным состоянием, а не данными, которые обязан переносить pg_upgrade.
Удаление SQL-объектов:
-- Выполните перед DROP, если нужно удалить и общий реестр учёта.
SELECT fasttrun_reset_temp_stats();
DROP EXTENSION fasttrun;DROP EXTENSION не выгружает уже загруженную библиотеку из backend. Для
полного отключения удалите fasttrun из shared_preload_libraries, если он там
есть, и перезапустите PostgreSQL. При ленивой или сессионной загрузке
переработайте старые соединения. Сам DROP EXTENSION и удаление из preload не удаляют
$PGDATA/pg_stat/fasttrun_temp_stats. Без предварительного сброса старые
счётчики могут загрузиться при следующем включении расширения.
Вызывайте fasttrun_reset_temp_stats() до удаления fasttrun из
shared_preload_libraries, пока общий реестр доступен. Если preload уже
отключён, остановите PostgreSQL и удалите файл вручную.
- Основной поддерживаемый контракт — самостоятельная локальная временная heap-таблица текущего backend.
- Секционированный родитель и родитель наследования отклоняются. Листовой раздел, который сам является heap-таблицей, или таблица-наследник без собственных потомков может быть принят, но fasttrun обработает только это отношение и не станет обходить иерархию.
- Внешние ключи не проверяются,
TRUNCATE ... CASCADEне выполняется. BEFORE TRUNCATEиAFTER TRUNCATEтриггеры не вызываются.DELETE-триггеры также не вызываются.- Последовательности SERIAL/IDENTITY не сбрасываются.
- Физическая очистка не откатывается транзакцией.
fasttruncate()публикуетreltuples=0. ЯдерныйTRUNCATEиспользует служебное значение-1, поэтому после повторного заполнения особенно важно вызватьfasttrun_analyze().- Расширенная статистика
CREATE STATISTICS, статистика выражений индексов и статистика наследования не собираются. - Старая каталожная статистика выражений индексов скрывается; до обычного
ANALYZEпланировщик использует оценки по умолчанию. - ACL, RLS и security-barrier поведение обычного
ANALYZEне воспроизводится. - Функции не проверяют владение таблицей и привилегии штатных
TRUNCATEиANALYZE; доступ нужно ограничивать правомEXECUTE. - Локальная статистика сохраняется между транзакциями одного backend, но исчезает при завершении соединения.
- После DML, зафиксированного без
fasttrun_analyze(), изменение распределения той же величины может остаться незамеченным. После каждого заполнения вызывайтеfasttrun_analyze(). - Локальные планы сбрасываются только в текущем backend. Глобальный
ResetPlanCacheне вызывается. - Отсутствующая таблица для основных функций считается допустимым случаем: функция ничего не делает.
- fasttrun не является границей безопасности между клиентами пулера.
Результат зависит от размера таблиц, числа столбцов и индексов, скорости хранилища, настроек PostgreSQL и размера кеша планов.
Основные ожидаемые эффекты:
fasttruncate()избегает общих сообщений об изменении файлов в стандартном режиме;fasttrun_analyze()не пишетpg_classиpg_statistic;- повторный analyze внутри одной транзакции обычно не сканирует таблицу;
invalidate_thresholdсокращает лишние обходы локального кеша планов;- запросы без временных таблиц не меняют планы и результаты.
Проверка check-no-temp-impact сравнивает планы, результаты, повторное
планирование и память для запросов без временных таблиц. После активации
локальных кешей вход в хук планировщика имеет небольшую, но не нулевую стоимость.
В измеренном сценарии она составляла около 0,26 мкс на планирование. Это
результат конкретного теста, а не универсальная гарантия.
Синтетический тест находится в sql/fasttrun_bench.sql. Для своей системы используйте реальные планы и нагрузочные тесты.
Пример наблюдаемого эффекта на одном из рабочих кластеров:
Графики показывают конкретный случай и не являются гарантией такого же результата на другой системе.
Развернуть команды и устройство тестов
Базовый набор:
make installcheck PG_CONFIG=/path/to/pg_configОн содержит 13 наборов pg_regress. На поддерживаемых PostgreSQL 16,
PostgreSQL 17 и PostgreSQL 18 ожидается результат 13/13.
Расширенный локальный набор:
make check-deep-local PG_CONFIG=/path/to/pg_configОн не заменяет полный обязательный pre-release прогон. Перед релизом и в ночном задании используется:
FT_CASSERT_TARGETS="16:/path/pg16/bin/pg_config:port:log,..." \
scripts/check_fasttrun_prerelease.shОбязательный набор включает cassert-сборки PostgreSQL 16/17/18, 13/13
pg_regress, BRIN stress, cache-init faults, fault matrix, проверки памяти,
планировщика и локальных инвалидаций.
Fault matrix выполняет 50 сценариев на 25 точках отказа. Короткий
scripts/check_fasttrun_brin_stress.sh делает 96 обычных и 48 принудительных
проверок планирования. Полный pre-release режим выполняет 1000 обычных и
200 принудительных проверок BRIN-пути на каждой версии PostgreSQL.
Полезные отдельные проверки:
make check-parity PG_CONFIG=/path/to/pg_config
make check-no-temp-impact PG_CONFIG=/path/to/pg_config
make check-zero-sinval PG_CONFIG=/path/to/pg_config
make check-fault-matrix PG_CONFIG=/path/to/pg_config
make check-brin-stress PG_CONFIG=/path/to/cassert/pg_config
make check-tracking-persistence PG_CONFIG=/path/to/pg_config
make check-required-suite
make check-docsСохранение файла учёта проверяет
scripts/check_fasttrun_tracking_persistence.sh.
make check-zero-sinval — отдельная Linux-проверка через gdb. Она считает
вызовы отправки общих сообщений и подтверждает, что основной путь fasttrun их
не создаёт. Каталожный тест из pg_regress не заменяет эту send-side проверку.
Она не входит в scripts/check_fasttrun_prerelease.sh, поэтому перед релизом её
нужно запускать отдельно на подходящем Linux-сервере.
В стандартном режиме fasttruncate() удаляет файлы локальной временной
таблицы и создаёт пустые заново. Локальные буферы принадлежат только текущему
backend, поэтому другим процессам не нужно сообщать об изменении этих файлов.
Индексы, TOAST и их метаданные перестраиваются в том же backend.
fasttrun_analyze() хранит оценки размера и статистику столбцов в памяти
backend. Хуки планировщика подставляют эти значения вместо старых каталожных
значений. Общий ResetPlanCache не используется; при необходимости планы
помечаются устаревшими только в текущем backend через PlanCacheRelCallback.
Хуки статистики устанавливаются лениво при первом создании локального кеша,
поэтому порядок fasttrun в shared_preload_libraries его не определяет.
Основные функции в стандартном режиме не изменяют pg_class,
pg_statistic и relfilenode целевой таблицы. Предварительное создание таблиц —
обычный DDL и не входит в этот контракт.
| PostgreSQL | Сборка | Базовые тесты |
|---|---|---|
| PostgreSQL 16 | да | 13/13 |
| PostgreSQL 17 | да | 13/13 |
| PostgreSQL 18 | да | 13/13 |
fasttrun.c # основной C-код
fasttrun.control # метаданные расширения
extension/ # SQL-файлы установки и обновления
Makefile # сборка через PGXS
examples/ # примеры интеграции
scripts/ # проверки и pre-release runner
sql/ # 13 наборов pg_regress
expected/ # ожидаемый вывод pg_regress

