Каждый администратор крупных информационных баз «1С:Предприятие 8» рано или поздно сталкивается с загадочными проблемами производительности при запуске системы. Представьте ситуацию: у вас есть две абсолютно идентичные копии базы данных на одном кластере серверов под управлением PostgreSQL. Одна база запускается за привычные 10–12 секунд, а вторая «зависает» на заставке почти на 30–40 минут.
При этом в отладчике мы четко видим, что процедура ПередНачаломРаботыСистемы() уже успешно завершилась, а клиентский обработчик ПриНачалеРаботыСистемы() еще даже не начинал выполняться. Давайте подробно разберем, что происходит в этот таинственный интервал времени, почему СУБД начинает совершать сотни тысяч операций чтения и как решить эту проблему раз и навсегда без утомительной выгрузки и загрузки базы данных (файла .dt).
Многие ошибочно полагают, что между завершением ПередНачаломРаботыСистемы() и стартом ПриНачалеРаботыСистемы() платформа простаивает или просто проверяет лицензии. На самом деле в этот момент платформа «1С:Предприятие» выполняет колоссальный объем скрытой работы по подготовке пользовательского интерфейса. Проанализируем эти процессы по шагам:
_SystemSettings, также известная как Хранилище системных настроек). Оттуда считываются индивидуальные параметры: настройки динамических списков, размеры и положения ранее открытых окон, история выбора элементов, избранное и персональные панели.ПриСозданииНаСервере. Если эти формы содержат тяжелые динамические списки, диаграммы, выборки задач, напоминаний или новостей, все соответствующие запросы к базе данных выполняются именно в этот момент — еще до того, как управление вернется на клиентскую сторону в процедуру ПриНачалеРаботыСистемы().Выясним причину, основываясь на данных мониторинга СУБД. Если в «здоровой» базе СУБД считывает около 8 000 блоков данных при старте, а в проблемной — более 300 000 блоков, это явный признак неоптимальной работы с дисковой подсистемой. Почему так происходит?
Основная причина кроется в особенностях архитектуры MVCC (Multi-Version Concurrency Control) в PostgreSQL и поведении системных таблиц «1С»:
Раздувание (Bloat) таблицы настроек. Таблица _systemsettings подвергается постоянным изменениям. Каждый раз, когда пользователь закрывает форму, меняет ширину колонки или выбирает элемент из списка, платформа перезаписывает настройки. В PostgreSQL при изменении строки старая версия физически не удаляется, а помечается как «мертвая». Если встроенная служба очистки (autovacuum) не справляется с нагрузкой, таблица настроек и её индексы раздуваются до гигантских размеров. При старте сеанса СУБД вместо быстрого поиска по индексу начинает выполнять полное сканирование таблицы (Seq Scan), перебирая миллионы «мертвых» строк в поисках актуальных настроек одного пользователя.
Устаревшая статистика планировщика. Если статистика по таблице _systemsettings или таблицам документов, выводимых на начальную страницу, давно не обновлялась, планировщик PostgreSQL выбирает неверный план выполнения запроса. Он считает, что таблица маленькая, и игнорирует индексы, что приводит к многоминутному сканированию диска.
Повреждение индексов СУБД. Локальное повреждение или сильная фрагментация индексов системных таблиц также заставляют PostgreSQL читать избыточные объемы данных с диска.
Выгрузка базы данных в файл .dt и последующая загрузка временно решают проблему только потому, что при загрузке вся структура таблиц создается заново, мертвые строки физически исчезают, а индексы перестраиваются с нуля. Однако это борьба с симптомами, а не с причиной.
Рассмотрим, как локализовать и подтвердить проблему с помощью штатных инструментов администратора.
Обычная настройка ТЖ, отслеживающая только системные ошибки или общие процессы, здесь не поможет. Нам нужно увидеть реальные SQL-запросы к СУБД и длительность их выполнения. Для этого отредактируем файл logcfg.xml. Обязательно добавим сбор событий DB и DBMS.
Создадим правильную структуру конфигурационного файла:
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="/1CData/tech_log" history="24">
<event>
<eq property="Name" value="DB"/>
<gt property="Duration" value="100000"/> <!-- Фильтруем запросы длиннее 0.1 сек -->
</event>
<event>
<eq property="Name" value="DBMS"/>
<gt property="Duration" value="100000"/>
</event>
<event>
<eq property="Name" value="EXCP"/>
</event>
<property name="all"/>
</log>
</config>
После применения этой настройки запустим проблемную базу. В полученных логах ТЖ мы анализируем свойство Duration. Ищем самый длительный запрос — именно он покажет имя таблицы СУБД (например, _systemsettings или _inforgXXXX), на которой спотыкается система.
В момент, когда запуск системы завис, откроем консоль управления PostgreSQL (pgAdmin или psql) и выполним следующий запрос для мониторинга активных транзакций:
SELECT
pid,
query,
state,
age(clock_timestamp(), query_start) AS duration
FROM pg_stat_activity
WHERE state <> 'idle' AND query NOT LIKE '%pg_stat_activity%';
Этот запрос наглядно продемонстрирует, какой именно SQL-запрос сейчас выполняется сервером баз данных и сколько времени он уже занимает. Если мы увидим запрос к таблице системных настроек со статусом активности, продолжающийся тысячи секунд, диагноз подтвержден.
Чтобы быстро проверить, не виноваты ли тяжелые запросы в формах рабочего стола, запустим систему из командной строки с использованием специального ключа:
1cv8.exe ENTERPRISE /F "ПутьКБазе" /DisableHomePageForms
Если с этим флагом база запустилась мгновенно, значит, проблема локализована в процедурах ПриСозданииНаСервере() одной из форм начальной страницы (например, вывод новостей, полнотекстовый поиск по всей базе или некорректно построенный динамический список документов).
Выяснив причину, перейдем к ее устранению непосредственно на уровне СУБД. Нам не нужно монопольно выгружать базу в файл .dt и тратить часы на ее развертывание. Выполним точечное обслуживание проблемной таблицы.
Если диагностика указала на раздувание системной таблицы настроек _systemsettings, подключимся к базе через pgAdmin под учетной записью суперпользователя СУБД и выполним последовательно три команды:
VACUUM FULL _systemsettings;
Важно: Эта команда заблокирует таблицу _systemsettings на запись, поэтому выполнять ее рекомендуется в период отсутствия активных пользователей в базе. Она полностью перепишет физический файл таблицы на диске, удалив все «мертвые» строки и вернув свободное место операционной системе.
REINDEX TABLE _systemsettings;
Эта команда воссоздаст все индексы для таблицы заново, устранив их возможные повреждения и фрагментацию.
ANALYZE _systemsettings;
Команда принудительно обновит статистические данные о распределении значений в таблице, позволяя планировщику PostgreSQL мгновенно строить оптимальные планы запросов (использовать быстрый Index Scan вместо тяжелого Seq Scan).
Чтобы избежать повторения этой проблемы в будущем, необходимо скорректировать настройки службы автоматической очистки PostgreSQL. В файле конфигурации postgresql.conf установим более агрессивные параметры для обработки быстроменяющихся таблиц:
# Порог срабатывания автовакуума в процентах от изменившихся строк
autovacuum_vacuum_scale_factor = 0.05
# Порог срабатывания обновления статистики в процентах от изменившихся строк
autovacuum_analyze_scale_factor = 0.02
# Минимальное количество изменившихся строк для запуска очистки
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
Такие параметры заставят PostgreSQL гораздо чаще чистить временные и системные таблицы «1С», не допуская их критического раздувания.
В процессе многолетней эксплуатации базы в таблице настроек накапливаются терабайты мусора от уволившихся сотрудников, старых вариантов отчетов и неиспользуемых оконных привязок. Рекомендуется периодически запускать встроенную обработку «Очистка настроек пользователей» (раздел «Администрирование» — «Настройки пользователей и прав» — «Очистка настроек»). Это позволит уменьшить физический объем хранимых данных и ускорить процедуру их инициализации при старте каждого сеанса.