Почему тормозит выборка из регистра цен в 1С на PostgreSQL и как это исправить

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При работе 1С с СУБД PostgreSQL системные администраторы и разработчики часто сталкиваются с ситуацией, когда после массового изменения данных (например, переоценки 10 000 позиций номенклатуры) типовые отчеты или обработки выгрузки начинают работать крайне медленно. В этой статье мы разберем, почему «простая» реиндексация не всегда помогает, как архитектура PostgreSQL влияет на скорость запросов 1С и что нужно изменить в коде и настройках сервера, чтобы вернуть производительность.

Анализируем причину: ловушка «запроса в цикле»

Первым делом проанализируем программный код. В ходе обсуждения выяснилось, что основной причиной катастрофического падения скорости стал классический антипаттерн разработки — выполнение запроса к базе данных внутри цикла. Рассмотрим, как это выглядит в коде:


// Неправильный подход, приводящий к тормозам
Для Каждого СтрокаТовара Из ТаблицаВыгрузки Цикл
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
        |ИЗ
        |	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, Номенклатура = &Номенклатура) КАК ЦеныНоменклатурыСрезПоследних";
    Запрос.УстановитьПараметр("Период", ТекущаяДата());
    Запрос.УстановитьПараметр("Номенклатура", СтрокаТовара.Номенклатура);
    
    Выборка = Запрос.Выполнить().Выбрать();
    // Обработка результата...
КонецЦикла;

Разберем, почему это критично для PostgreSQL. В отличие от других СУБД, PostgreSQL несет существенные накладные расходы на каждое установление соединения и парсинг запроса. Когда мы выполняем 10 000 отдельных запросов, сервер тратит больше времени на обслуживание самого процесса вызова, чем на поиск данных.

Решение: всегда переписывайте такие участки кода на один пакетный запрос. Мы должны сначала подготовить список всей нужной номенклатуры, передать его в запрос как массив и получить все цены одним махом, после чего сопоставить их в памяти 1С.


// Правильный подход: один запрос на все позиции
МассивНоменклатуры = ТаблицаВыгрузки.ВыгрузитьКолонку("Номенклатура");

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЦеныНоменклатурыСрезПоследних.Номенклатура КАК Номенклатура,
    |	ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
    |ИЗ
    |	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, Номенклатура В (&МассивНоменклатуры)) КАК ЦеныНоменклатурыСрезПоследних";
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);

РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Дальше работаем с таблицей значений в памяти

Механизм MVCC и «раздувание» таблиц (Bloat)

Выясним причину, по которой проблема обостряется именно после массовой переоценки. PostgreSQL использует механизм многоверсионности (MVCC). Когда 1С обновляет строку в регистре сведений (или удаляет и записывает новую), старая версия строки не удаляется физически. Она помечается как «мертвая» (dead tuple).

При переоценке 10 000 товаров в базе появляется 10 000 «мертвых» записей. Если такие операции проводятся часто, физический размер таблицы и ее индексов начинает расти («пухнуть»), хотя логическое количество записей остается прежним. Индексы становятся «дырявыми», и планировщик PostgreSQL при выполнении запроса вынужден считывать гораздо больше страниц с диска.

Именно поэтому в рассматриваемой ситуации помог «перелив» базы через бэкап: команда pg_dump и последующее восстановление физически пересоздают таблицы без лишнего мусора.

Регламентное обслуживание: VACUUM и ANALYZE

Чтобы не прибегать к радикальным мерам вроде удаления кластера, необходимо правильно использовать встроенные инструменты обслуживания. Рассмотрим разницу между ключевыми командами:

  1. VACUUM: Проходит по таблице, находит «мертвые» строки и помечает их место как свободное для будущих записей. Это предотвращает бесконечный рост файлов.
  2. ANALYZE: Собирает статистику о распределении данных в таблице. Планировщик запросов использует эти данные, чтобы решить, какой индекс использовать эффективнее.

Для баз 1С рекомендуется запускать их совместно. Команда VACUUM ANALYZE выполняет очистку и сразу обновляет статистику. Если тормозит конкретная таблица (регистр), можно запустить команду для нее:

VACUUM ANALYZE имя_таблицы_субд;

Для определения имени таблицы в СУБД из 1С используйте функцию ПолучитьСтруктуруХраненияБазыДанных(). Это позволит вам точно знать, какой объект в PostgreSQL соответствует вашему регистру сведений.

Оптимизация PostgreSQL для работы на SSD

Проанализируем ситуацию с ресурсами. Если ваша база данных расположена на SSD (как у автора вопроса), стандартные настройки PostgreSQL могут работать против вас.

Посмотрите на параметр random_page_cost в файле postgresql.conf. По умолчанию он равен 4.0. Это значение рассчитано на старые HDD, где случайное чтение обходится дорого. Для SSD этот параметр следует установить в значение 1.1 или 1.0.

Если оставить 4.0, PostgreSQL будет «думать», что использовать индекс (который требует случайного доступа к страницам) — это очень дорогое удовольствие. В итоге он может выбрать Sequential Scan (полное сканирование таблицы) там, где индекс отработал бы мгновенно. Это одна из частых причин внезапных тормозов после изменения объема данных.

Настройка Autovacuum для высоконагруженных баз 1С

Чтобы не запускать VACUUM вручную каждую ночь, настроим автоматическую очистку более агрессивно. Стандартные настройки запускают автовакуум, когда изменяется 20% данных в таблице. Для регистра с миллионами записей 20% — это слишком много.

Рекомендуем изменить следующие параметры в настройках сервера:

Итоги и последовательность действий

Если вы столкнулись с резким замедлением запросов к регистру в PostgreSQL, выполните следующие шаги:

  1. Проверьте код 1С: убедитесь, что вы не вызываете запросы к этому регистру внутри циклов. Используйте пакетную выборку.
  2. Обновите статистику: выполните команду ANALYZE для проблемной таблицы. Это заставит СУБД перестроить план запроса.
  3. Выполните очистку: запустите VACUUM для удаления «мертвых» строк, возникших после массовой переоценки.
  4. Проверьте random_page_cost: убедитесь, что настройки соответствуют вашему дисковому массиву (SSD).

Помните, что PostgreSQL требует более внимательного отношения к регламентному обслуживанию, чем MS SQL Server, но при правильной настройке и оптимизации кода 1С он показывает отличную производительность даже на больших объемах данных.

← На главную