В процессе эксплуатации крупных и средних информационных баз на платформе 1С:Предприятие 8.3 в связке с СУБД PostgreSQL специалисты часто сталкиваются с загадочным явлением: запросы к виртуальным таблицам остатков и оборотов регистра бухгалтерии начинают работать крайне медленно, начиная с некоторой «проблемной даты». До этой даты остатки получаются мгновенно (за доли секунды), а после неё — выполнение запроса затягивается на минуты.
Рассмотрим природу этой проблемы, проанализируем, почему стандартные средства обслуживания не всегда помогают, и разберем наиболее эффективный программный метод восстановления производительности.
Выясним, как проявляется данная аномалия. Типичная ситуация выглядит следующим образом: при выполнении запроса к виртуальной таблице РегистрБухгалтерии.Хозрасчетный.Остатки на определенную дату (например, 10 мая) система отрабатывает штатно. Однако, если изменить параметр даты всего на одну секунду вперед, время выполнения возрастает в десятки раз. При этом физических записей в регистре на эту секунду может и не быть.
Проанализируем основные признаки:
.dt и загрузка обратно «лечит» базу, так как при этом происходит полная пересборка таблиц итогов.Посмотрим на пример кода, который в проблемной базе может выполняться недопустимо долго:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.Счет,
| ХозрасчетныйОстатки.СуммаОстаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&ДатаОстатков, , , ) КАК ХозрасчетныйОстатки";
// Если ДатаОстатков = '20240416103945', выполняется 2 секунды
// Если ДатаОстатков = '20240416103946', выполняется 60 секунд
Запрос.УстановитьПараметр("ДатаОстатков", Объект.НужнаяДата);
Результат = Запрос.Выполнить();
Разберем основные причины деградации производительности 1С на PostgreSQL в данном контексте. Главная проблема кроется в особенностях работы планировщика запросов PostgreSQL и механизма хранения итогов в 1С.
1. Раздувание (Bloat) таблиц итогов. Таблицы итогов (_AccRgTotals) в 1С подвергаются постоянным операциям UPDATE и INSERT. В PostgreSQL из-за механизма MVCC (многоверсионность) при каждом обновлении строки создается её новая версия, а старая помечается как «мертвая». Если процесс очистки (autovacuum) не успевает обрабатывать эти изменения, таблица «раздувается», и планировщик может решить, что полное сканирование таблицы (Sequential Scan) будет эффективнее использования индекса.
2. Некорректная статистика. PostgreSQL собирает статистику распределения данных в колонках. Если данные в регистре распределены неравномерно (например, после определенной даты плотность записей резко меняется), планировщик может построить неоптимальный план запроса. Реструктуризация сбрасывает эту статистику и пересоздает индексы «с чистого листа».
3. Аномальные даты. Одной из скрытых причин может быть наличие в базе записей с «будущими» датами (например, документ от 2099 года). 1С хранит итоги на актуальную дату, и наличие таких записей заставляет систему выполнять избыточные вычисления при получении текущих остатков.
Как показывает практика, существует способ «починить» итоги значительно быстрее, чем через полную реструктуризацию всей информационной базы. Рассмотрим метод программного управления итогами регистра бухгалтерии. Суть метода заключается в принудительном отключении использования итогов, что физически очищает соответствующие таблицы БД, и их последующем включении с полным пересчетом.
Рассмотрим по шагам выполнение этой операции для регистра Хозрасчетный:
Процедура ВосстановитьПроизводительностьИтогов() Экспорт
Регистр = РегистрыБухгалтерии.Хозрасчетный;
// Шаг 1: Полностью отключаем использование итогов.
// Это приводит к физической очистке таблиц итогов в PostgreSQL.
Регистр.УстановитьИспользованиеИтогов(Ложь);
Регистр.УстановитьИспользованиеТекущихИтогов(Ложь);
// Шаг 2: Включаем использование итогов обратно.
// Платформа создаст пустые структуры, готовые к заполнению.
Регистр.УстановитьИспользованиеИтогов(Истина);
Регистр.УстановитьИспользованиеТекущихИтогов(Истина);
// Шаг 3: Выполняем полный пересчет.
// Система заново рассчитает данные на основе записей регистра (движений).
Регистр.ПересчитатьИтоги();
Регистр.ПересчитатьТекущиеИтоги();
Сообщить("Пересчет итогов завершен успешно!");
КонецПроцедуры
Важный нюанс: Этот метод работает гораздо эффективнее штатного «Тестирования и исправления», так как команда УстановитьИспользованиеИтогов(Ложь) выполняет операцию, аналогичную TRUNCATE или массовому удалению записей в таблицах итогов, что радикально устраняет проблему «раздувания» (bloat) и фрагментации индексов именно для этого объекта.
Проанализируем, что еще можно сделать на уровне системного администрирования, чтобы проблема не повторялась:
FILLFACTOR на уровне 70-80. Это зарезервирует место внутри страниц данных для будущих обновлений, предотвращая преждевременную фрагментацию.autovacuum_vacuum_scale_factor и autovacuum_analyze_scale_factor в postgresql.conf в меньшую сторону (например, до 0.01 или 0.02), чтобы СУБД чаще очищала таблицы, в которых меняется много данных.ALTER TABLE _AccRgTotals123 ALTER COLUMN _Period SET STATISTICS 1000;
ANALYZE этой таблицы.Если вы столкнулись с резким замедлением запросов к итогам регистра бухгалтерии после конкретной даты, не спешите запускать полную реструктуризацию базы на много часов. Сначала проверьте базу на наличие документов с ошибочными датами в далеком будущем. Если их нет, воспользуйтесь приведенным выше программным кодом для сброса и пересчета итогов. В большинстве случаев это решает проблему за считанные минуты, возвращая производительность системы к исходным показателям.