Как правильно получить дату и номер документа в запросе 1С 7.7 без потери производительности?

Программист 1С v7.7
← На главную

При разработке отчетов в платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с ситуацией, когда попытка получить реквизиты документа-регистратора (такие как дата и номер) непосредственно в тексте запроса приводит к драматическому падению скорости работы программы. Запрос, выполнявшийся за 1 секунду, при добавлении обращений к дате и номеру документа начинает выполняться 50 секунд и более.

Рассмотрим подробно причины такого поведения встроенного ("черного") движка запросов 1С 7.7 и проанализируем штатные способы решения этой задачи.

В чем причина падения производительности в 1С 7.7?

Проанализируем пример кода, в котором разворачивается группировка по регистратору с попыткой вытащить номер и дату документа через составное обращение:


ЗП = СоздатьОбъект("Запрос");
ТЗ = "Период с НачДата По КонДата;
|Склад = Регистр.Прибыль.Склад;
|Товар = Регистр.Прибыль.Товар;
|Количество = Регистр.Прибыль.Количество;
|ТекДок = Регистр.Прибыль.ТекущийДокумент;
|ТекДокНомерДок = Регистр.Прибыль.ТекущийДокумент.ЗакрытиеСмены.НомерДок,
|                Регистр.Прибыль.ТекущийДокумент.НакладнаяРасход.НомерДок, 
|                Регистр.Прибыль.ТекущийДокумент.ОтчетРеализатора.НомерДок;
|ТекДокДатаДок =  Регистр.Прибыль.ТекущийДокумент.ЗакрытиеСмены.ДатаДок,
|                Регистр.Прибыль.ТекущийДокумент.НакладнаяРасход.ДатаДок, 
|                Регистр.Прибыль.ТекущийДокумент.ОтчетРеализатора.ДатаДок;
|Группировка ТекДок;
|Функция Продано = Сумма(Количество);";

Выясним причину замедления на уровне СУБД в клиент-серверном режиме (MS SQL Server):

  1. Поскольку реквизит ТекущийДокумент в регистре имеет составной тип («Документ неопределенного вида»), платформа не может извлечь номер и дату напрямую из одной таблицы.
  2. При перечислении видов документов через запятую генератор SQL-запросов платформы добавляет левые соединения (LEFT OUTER JOIN) к таблицам шапок (DH*) для каждого указанного вида документа.
  3. При согласовании множества таблиц на больших объемах таблиц движений регистра (RA*) оптимизатор SQL Server прекращает эффективно использовать индексы, переходя к полному сканированию таблиц (Table Scan). В итоге время выполнения запроса возрастает в десятки раз.

Решение 1. Получение даты и номера документа при обходе результатов запроса

Самый простой и эффективный штатный способ — вынести получение даты и номера документа из самого текста запроса в цикл обработки выборки.

Посмотрим, как выглядит оптимизированный текст запроса:


ЗП = СоздатьОбъект("Запрос");
ТЗ = "Период с НачДата По КонДата;
|Склад = Регистр.Прибыль.Склад;
|Товар = Регистр.Прибыль.Товар;
|Количество = Регистр.Прибыль.Количество;
|ТекДок = Регистр.Прибыль.ТекущийДокумент;
|Группировка Склад Без Групп;
|Группировка Товар Без Групп;
|Группировка ТекДок;
|Функция Продано = Сумма(Количество);";

Если ЗП.Выполнить(ТЗ) = 1 Тогда
    Пока ЗП.Группировка("Склад") = 1 Цикл
        Пока ЗП.Группировка("Товар") = 1 Цикл
            Пока ЗП.Группировка("ТекДок") = 1 Цикл
                // Получаем дату и номер штатно через объект документа
                ДокДата  = ЗП.ТекДок.ДатаДок;
                ДокНомер = ЗП.ТекДок.НомерДок;
                
                // Выводим данные в таблицу или обрабатываем дальше
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;
КонецЕсли;

При таком подходе сам запрос выполняется за считанные секунды. При обходе группировки ТекДок платформа быстро выбирает точные данные по конкретному IDDOC из кэша или точечным SQL-запросом.

Решение 2. Хранение даты и номера документа в реквизитах регистра

Если отчет по регистру строится часто и за большие периоды, рационально изменить структуру регистра в Конфигураторе:

  1. Добавим в регистр Прибыль новые реквизиты: ДатаДокумента (тип "Дата") и НомерДокумента (тип "Строка").
  2. При проведении документов-регистраторов заполним эти реквизиты значениями ДатаДок и НомерДок.
  3. Обратимся к данным реквизитам напрямую в тексте запроса:

|ТекДокДата  = Регистр.Прибыль.ДатаДокумента;
|ТекДокНомер = Регистр.Прибыль.НомерДокумента;

В этом случае данные читаются напрямую из таблицы движений регистра RA* без выполнения дополнительных операторов JOIN, что дает максимальную скорость выполнения.

Решение 3. Использование флага "Быстрая обработка движений"

Разберем еще одну штатную возможность платформы. Если у регистра включено свойство "Быстрая обработка движений" (или установлены галки отбора по измерениям), платформа оптимизирует выборку регистраторов. Тем не менее, использование прямых реквизитов или обработка в цикле остаются предпочтительными методами для достижения наибольшего быстродействия.

Резюме: Избегайте перечисления конструкций вида ТекущийДокумент.ВидДок.НомерДок через запятую в тексте встроенных запросов 1С 7.7. Для получения высокой скорости извлекайте в запросе сам объект ТекущийДокумент, а его реквизиты читайте при выгрузке или обходе результатов выборки.

← На главную