Почему тормозит листание списка документов в 1С на MS SQL Server и как это исправить

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При работе с большими таблицами документов (миллионы записей) пользователи нередко сталкиваются с задержками при постраничном листании списков клавишами Page Down или Page Up. Задержка в 1.5–2 секунды на каждую страницу делает интерактивную работу некомфортной, даже если сервер СУБД оснащен достаточным объемом оперативной памяти и быстрыми дисками SSD. Разберем детально механизм формирования запросов платформой 1С к MS SQL Server, выясним причины деградации производительности и рассмотрим способы устранения проблемы.

Анализ проблемы и поведение оптимизатора СУБД

Проанализируем ситуацию: при просмотре трассировки в SQL Server Profiler фиксируются длительные запросы с выборкой первых строк (TOP). В тексте запроса, который платформа автоматически генерирует для позиционирования курсора списка, присутствует сложная конструкция с несколькими условиями OR:


SELECT TOP 48
_DocumentJournal7838_R._Date_Time AS _A1,
_DocumentJournal7838_R._Number AS _A2,
_DocumentJournal7838_R._Fld7841 AS _A3,
_DocumentJournal7838_R._DocumentTRef AS _A4TRef,
_DocumentJournal7838_R._DocumentRRef AS _A4RRef,
_DocumentJournal7838_R._Marked AS _A5,
_DocumentJournal7838_R._Posted AS _A6
FROM
_DocumentJournal7838 _DocumentJournal7838_R WITH(NOLOCK)
WHERE
_DocumentJournal7838_R._DocumentRRef > @P1 AND _DocumentJournal7838_R._Date_Time = @P2 AND _DocumentJournal7838_R._DocumentTRef = @P3 AND _DocumentJournal7838_R._Date_Time >= @P4 AND _DocumentJournal7838_R._Date_Time <= @P5 OR
_DocumentJournal7838_R._DocumentTRef > @P6 AND _DocumentJournal7838_R._Date_Time = @P7 AND _DocumentJournal7838_R._Date_Time >= @P8 AND _DocumentJournal7838_R._Date_Time <= @P9 OR
_DocumentJournal7838_R._Date_Time > @P10 AND _DocumentJournal7838_R._Date_Time >= @P11 AND _DocumentJournal7838_R._Date_Time <= @P12
ORDER BY
_DocumentJournal7838_R._Date_Time,
_DocumentJournal7838_R._DocumentTRef,
_DocumentJournal7838_R._DocumentRRef

Посмотрим на план выполнения этого запроса. В технологическом журнале и плане SQL Server операция отображается как Clustered Index Scan (сканирование кластерного индекса) вместо точечного поиска Clustered Index Seek:

  1. Влияние дизъюнкций (OR): Наличие составных условий через OR не позволяет оптимизатору СУБД однозначно вычислить диапазон поиска для индексного поиска (Seek). В результате оптимизатор решает последовательно сканировать таблицу с начала диапазона в расчете на то, что условие TOP быстро прервет операцию.
  2. Неравномерность распределения данных: Если плотность записей высока (например, свежие документы за текущий месяц), сканирование действительно быстро находит 50 записей и завершается. Но как только пользователь перемещается к разреженным периодам (начало года, архивные периоды), СУБД приходится физически считывать миллионы индексных страниц, пока не наберется запрошенное число строк, что вызывает рост логических чтений и падение скорости.
  3. Эффект Parameter Sniffing: План со сканированием, скомпилированный для плотного интервала, оседает в процедурном кэше СУБД и повторно применяется к диапазонам, где он крайне неэффективен.

Основное решение: отключение устаревшего режима совместимости платформы

Выясним причину появления неоптимального SQL-кода. В старых версиях платформы 1С (в частности, в 8.1 и конфигурациях с установленным Режимом совместимости с версией 8.1) транслятор запросов списков формировал единый запрос со сложной дизъюнкцией для вычисления границ курсора.

Начиная с платформы 8.2 (без совместимости с 8.1) и во всех последующих версиях механизм позиционирования в обычных формах (ЖурналДокументовСписок, ДокументСписок) был переработан. Рассмотрим, как изменяется запрос после снятия режима совместимости:


SELECT TOP 43
T2._Date_Time,
T2._Fld7841,
T2._DocumentTRef,
T2._DocumentRRef,
T2._Marked,
T2._Posted
FROM _DocumentJournal7838 T2 WITH(NOLOCK)
WHERE ((T2._Date_Time >= @P1) AND (T2._Date_Time <= @P2)) AND T2._Date_Time = @P3 AND T2._DocumentTRef > @P4
ORDER BY (T2._Date_Time) ASC, (T2._DocumentTRef) ASC, (T2._DocumentRRef) ASC
OPTION (FAST 1)

Разберем ключевые изменения в новом плане:

  1. Переход к Index Seek: Устранение конструкции OR позволяет СУБД использовать стандартный индекс по дате и ссылке для точечного позиционирования.
  2. Указание хинта OPTION (FAST n): Директива OPTION (FAST 1) прямо предписывает оптимизатору SQL Server построить план, минимизирующий время возврата первых строк набора, исключая долгий просмотр таблиц.

Дополнительные методы оптимизации списков документов

Если быстрое обновление режима совместимости невозможно по архитектурным причинам, применим сопутствующие методы ускорения работы со списками на СУБД:

  1. Установка интервала журнала по умолчанию: Установка фильтра по периоду (например, текущий месяц или квартал) через свойства списка НачалоИнтервала и КонецИнтервала жестко ограничивает блок WHERE по полю даты, предотвращая сканирование всей исторической глубины таблицы.
  2. Исключение лишних полей и тяжелых представлений: Убедимся, что в список не выводятся реквизиты, требующие обращения к кластерному индексу или выполнения множественных неявных подзапросов для получения представлений ссылочных типов.
  3. Контроль сортировки: Кластерный индекс журнала документов сформирован по полям Дата/Время + ТипДокумента + Ссылка. При установке пользовательской сортировки по другим колонкам (например, по номеру или контрагенту) СУБД вынуждена использовать некластерный индекс с операциями Key Lookup, что многократно увеличивает нагрузку на дисковую подсистему.
  4. Обслуживание индексов и процедурного кэша: Регулярная дефрагментация или реорганизация индексов таблицы журнала с актуализацией статистики обеспечивает корректный выбор планов оптимизатором. При резком зависании запросов сброс плана по конкретному хэндлу или выполнение DBCC FREEPROCCACHE временно устраняет влияние некорректного кэширования параметров.
← На главную