Переход со старых версий PostgreSQL (например, 10-й) на современные (16-ю или 17-ю) в связке с платформой 1С:Предприятие 8.3 часто обещает значительный прирост производительности. Однако на практике системные администраторы нередко сталкиваются с обратным эффектом: операции проведения документов, которые раньше выполнялись мгновенно, начинают занимать десятки секунд. Особенно остро эта проблема проявляется в таблицах регистров бухгалтерии (_AccRg).
Разберем детально, почему это происходит, проанализируем планы запросов и найдем конкретные шаги для восстановления быстродействия системы.
Первым делом нам необходимо выяснить, на что именно PostgreSQL тратит время. Проанализируем типичный план запроса SELECT к таблице регистра бухгалтерии, который в новой версии выполняется за 35-40 мс вместо привычных 1 мс.
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM _AccRg12303
WHERE _Period > '2025-01-01' LIMIT 100;
Limit (actual time=35.878..36.209 rows=100 loops=1)
Buffers: shared hit=3494 read=24
-> Index Scan using _accrg12303_10 on _accrg12303 (cost=0.42..27251.54 rows=47497 width=464)
Обратим внимание на показатель Buffers: shared hit=3494. Это означает, что для получения всего 100 строк PostgreSQL пришлось прочитать из кэша памяти 3494 страницы (каждая по 8 КБ), что суммарно составляет около 27.5 МБ данных. Рассмотрим, почему это критично:
SELECT *, СУБД не может ограничиться данными только из индекса (Index Only Scan) и вынуждена для каждой строки обращаться к основной таблице (Heap).При переносе базы данных через pg_dump и pg_restore может произойти скрытая подмена основного индекса, по которому кластеризована таблица. Проанализируем структуру индексов на старом и новом серверах. Выяснится, что на PostgreSQL 10 использовался индекс _accrg12303_1, а на PostgreSQL 16 — _accrg12303_10, который включает дополнительные поля.
Это приводит к тому, что физический порядок записей на диске перестает соответствовать порядку, в котором 1С запрашивает данные. Чтобы исправить это, выполним принудительную перегруппировку данных:
-- Указываем СУБД, какой индекс использовать для физического упорядочивания
CLUSTER _AccRg12303 USING _accrg12303_1;
-- Обновляем статистику для планировщика
ANALYZE _AccRg12303;
-- Прогреваем кэш, чтобы исключить влияние дисковой подсистемы
SELECT pg_prewarm('_accrg12303');
Важно помнить, что команда CLUSTER блокирует таблицу на чтение и запись, поэтому ее следует выполнять в технологическое окно.
Современные версии PostgreSQL по умолчанию настроены на работу с медленными HDD-дисками. Параметр random_page_cost (стоимость произвольного чтения) по умолчанию равен 4.0, в то время как seq_page_cost (последовательное чтение) равен 1.0. Для быстрых NVMe-накопителей такая разница лишена смысла.
Разберем, как изменить настройки в postgresql.conf, чтобы планировщик перестал «бояться» индексного сканирования:
random_page_cost = 1.1. Это заставит планировщик чаще выбирать индексы, понимая, что прыжки по блокам данных на NVMe стоят почти столько же, сколько последовательное чтение.effective_io_concurrency. Для NVMe его можно смело увеличивать до 200-300, что позволит СУБД лучше использовать параллелизм дисковой подсистемы.Если ваш сервер PostgreSQL запущен внутри виртуальной машины под управлением Hyper-V, причиной замедления могут быть микрозадержки при системных вызовах времени. В PostgreSQL 12 и выше механизмы блокировок и транзакций чаще обращаются к системным часам.
Проверим текущий источник времени в Linux командой:
cat /sys/devices/system/clocksource/clocksource0/current_clocksource
Если вы видите значение hpet или acpi_pm, это может замедлять каждый шаг выполнения запроса на миллисекунды. Для Hyper-V крайне рекомендуется использовать tsc. Настройка производится через параметры загрузки ядра (GRUB):
GRUB_CMDLINE_LINUX_DEFAULT="... clocksource=tsc"
Ситуация, когда на одном сервере PostgreSQL размещено 460 баз данных (как в рассматриваемом случае), создает колоссальную нагрузку на разделяемую память (Shared Buffers) и системный каталог метаданных. В новых версиях PostgreSQL механизмы работы с блокировками в памяти стали более чувствительны к количеству объектов.
Рассмотрим рекомендации для такой конфигурации:
shared_buffers.LWLocks (легковесные блокировки).jit = offПри использовании платформы 8.3.24+ важно убедиться, что модули online_analyze и plantuner (входящие в сборки от 1С или Postgres Pro) работают корректно. После массовой загрузки данных или реструктуризации статистика может не обновиться мгновенно, что приведет к выбору ошибочного плана Sequential Scan вместо Index Scan.
Проанализируем ситуацию с записью: если DELETE или INSERT в таблицу _AccRg занимают более 2 секунд, это явный признак того, что СУБД не использует индекс для поиска существующих записей. В этом случае помогает не просто реструктуризация, а полное удаление и создание индексов заново, либо выполнение VACUUM (ANALYZE, FREEZE).
Подводя итог, можно сказать, что замедление в 200 раз — это результат каскадного эффекта: неоптимальные индексы после миграции, завышенная стоимость чтения для планировщика и накладные расходы виртуализации. Последовательное применение описанных выше настроек позволяет вернуть производительность к показателям PostgreSQL 10 и даже превзойти их.