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

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С 7.7 программисты часто сталкиваются с проблемой производительности штатных (так называемых «черных») запросов. Типичная ситуация: имеется готовый СписокЗначений, содержащий ссылки на документы, и необходимо получить данные по этим документам. Стандартная конструкция запроса с фильтром Условие(Док в СписокДокументов) зачастую работает крайне медленно, особенно если не указан жесткий период или база данных имеет внушительный объем. Рассмотрим подробнее, почему это происходит, и проанализируем эффективные способы решения этой задачи.

Причина низкой скорости штатных запросов

Разберем, как работает движок запросов 1С 7.7. Когда мы используем Условие, система выполняет последовательное сканирование таблиц базы данных. Если период в запросе не ограничен, 1С начинает просмотр журнала документов с самого начала эксплуатации базы. Даже если в вашем списке всего 10 документов, но база ведется 10 лет, запрос может «просматривать» сотни тысяч записей, проверяя каждую на соответствие вашему списку. Проанализируем основные стратегии оптимизации.

Решение 1: Оптимизация штатного запроса через границы периода

Самый простой и быстрый способ ускорить выполнение штатного запроса без существенного переписывания кода — это программное ограничение периода. Выясним причину: если мы укажем точные границы периода, в которые попадают все документы из списка, 1С будет сканировать только этот интервал в таблице _1SJOURN.

Рассмотрим алгоритм реализации:

  1. Обойдем имеющийся список документов и определим минимальную и максимальную даты.
  2. Установим эти даты в конструкцию Период с ... по ... текста запроса.
  3. Оставим условие вхождения в список для фильтрации конкретных объектов.

Пример кода для вычисления границ:


МинДата = '31.12.3999';
МаксДата = '01.01.1980';
Для к = 1 По СписокДокументов.РазмерСписка() Цикл
    ТекДок = СписокДокументов.ПолучитьЗначение(к);
    Если ТекДок.ДатаДок < МинДата Тогда
        МинДата = ТекДок.ДатаДок;
    КонецЕсли;
    Если ТекДок.ДатаДок > МаксДата Тогда
        МаксДата = ТекДок.ДатаДок;
    КонецЕсли;
КонецЦикла;

ТекстЗапроса = "
|Период с МинДата по МаксДата;
|ТекущийДок = Документ.РасходнаяНакладная.ТекущийДокумент;
|Условие(ТекущийДок в СписокДокументов);
|Группировка ТекущийДок;";

Решение 2: Использование Индексированных Таблиц Значений (ИТЗ)

Если штатный запрос все равно работает неудовлетворительно или требуется сложная группировка данных, рассмотрим вариант с использованием объекта ИндексированнаяТаблицаЗначений (доступен при использовании внешних компонент, например, 1С++). Этот метод позволяет избежать «черного» запроса как такового.

Проанализируем ситуацию: мы можем напрямую перебрать наш СписокЗначений, получить необходимые реквизиты каждого документа и выгрузить их в ИТЗ. Индексированная таблица позволяет мгновенно выполнять группировки и сортировки в оперативной памяти, что заменяет функционал объекта Запрос.

Разберем пример реализации:


ТабДанных = СоздатьОбъект("ИндексированнаяТаблицаЗначений");
ТабДанных.НоваяКолонка("Документ");
ТабДанных.НоваяКолонка("Сумма", "Число");
// Добавляем другие нужные колонки

СписокДокументов.ВыбратьЗначения();
Пока СписокДокументов.ПолучитьЗначение(к, ТекДок) = 1 Цикл
    ТабДанных.НоваяСтрока();
    ТабДанных.Документ = ТекДок;
    ТабДанных.Сумма = ТекДок.Итог("Сумма"); 
КонецЦикла;

// Теперь мы можем сгруппировать данные так же быстро, как в запросе
ТабДанных.Сгруппировать("Документ", "Сумма");

Важный момент: чтобы не переписывать алгоритм вывода отчета, который завязан на обход группировок запроса, мы можем эмулировать поведение запроса, перебирая строки ИТЗ методами ВыбратьСтроки() и ПолучитьСтроку().

Решение 3: Прямые SQL-запросы

Для баз данных, работающих на SQL Server, наиболее эффективным методом является использование прямых запросов (компонента 1С++). Посмотрим на пример ситуации: когда документов в списке более 10 000, штатные методы становятся нежизнеспособными.

В прямом запросе мы можем передать список идентификаторов документов (IDDOC) непосредственно в SQL-инструкцию WHERE ... IN (...). Однако, стоит помнить, что SQL имеет ограничения на длину строки запроса. Рассмотрим более надежный способ — использование временных таблиц.

  1. Создадим временную таблицу в SQL-памяти.
  2. Загрузим в нее IDDOC из нашего списка.
  3. Выполним JOIN (соединение) основной таблицы журнала документов (_1SJOURN) с этой временной таблицей.

Такой подход позволяет SQL-серверу использовать индексы по полю IDDOC, благодаря чему данные возвращаются практически мгновенно.

Решение 4: Объектный обход выборки

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

Резюме:

Для ускорения работы в 1С 7.7 при наличии готового списка документов мы рекомендуем:

← На главную