В процессе разработки на платформе 1С 7.7 программисты часто сталкиваются с проблемой производительности штатных (так называемых «черных») запросов. Типичная ситуация: имеется готовый СписокЗначений, содержащий ссылки на документы, и необходимо получить данные по этим документам. Стандартная конструкция запроса с фильтром Условие(Док в СписокДокументов) зачастую работает крайне медленно, особенно если не указан жесткий период или база данных имеет внушительный объем. Рассмотрим подробнее, почему это происходит, и проанализируем эффективные способы решения этой задачи.
Разберем, как работает движок запросов 1С 7.7. Когда мы используем Условие, система выполняет последовательное сканирование таблиц базы данных. Если период в запросе не ограничен, 1С начинает просмотр журнала документов с самого начала эксплуатации базы. Даже если в вашем списке всего 10 документов, но база ведется 10 лет, запрос может «просматривать» сотни тысяч записей, проверяя каждую на соответствие вашему списку. Проанализируем основные стратегии оптимизации.
Самый простой и быстрый способ ускорить выполнение штатного запроса без существенного переписывания кода — это программное ограничение периода. Выясним причину: если мы укажем точные границы периода, в которые попадают все документы из списка, 1С будет сканировать только этот интервал в таблице _1SJOURN.
Рассмотрим алгоритм реализации:
Период с ... по ... текста запроса.Пример кода для вычисления границ:
МинДата = '31.12.3999';
МаксДата = '01.01.1980';
Для к = 1 По СписокДокументов.РазмерСписка() Цикл
ТекДок = СписокДокументов.ПолучитьЗначение(к);
Если ТекДок.ДатаДок < МинДата Тогда
МинДата = ТекДок.ДатаДок;
КонецЕсли;
Если ТекДок.ДатаДок > МаксДата Тогда
МаксДата = ТекДок.ДатаДок;
КонецЕсли;
КонецЦикла;
ТекстЗапроса = "
|Период с МинДата по МаксДата;
|ТекущийДок = Документ.РасходнаяНакладная.ТекущийДокумент;
|Условие(ТекущийДок в СписокДокументов);
|Группировка ТекущийДок;";
Если штатный запрос все равно работает неудовлетворительно или требуется сложная группировка данных, рассмотрим вариант с использованием объекта ИндексированнаяТаблицаЗначений (доступен при использовании внешних компонент, например, 1С++). Этот метод позволяет избежать «черного» запроса как такового.
Проанализируем ситуацию: мы можем напрямую перебрать наш СписокЗначений, получить необходимые реквизиты каждого документа и выгрузить их в ИТЗ. Индексированная таблица позволяет мгновенно выполнять группировки и сортировки в оперативной памяти, что заменяет функционал объекта Запрос.
Разберем пример реализации:
ТабДанных = СоздатьОбъект("ИндексированнаяТаблицаЗначений");
ТабДанных.НоваяКолонка("Документ");
ТабДанных.НоваяКолонка("Сумма", "Число");
// Добавляем другие нужные колонки
СписокДокументов.ВыбратьЗначения();
Пока СписокДокументов.ПолучитьЗначение(к, ТекДок) = 1 Цикл
ТабДанных.НоваяСтрока();
ТабДанных.Документ = ТекДок;
ТабДанных.Сумма = ТекДок.Итог("Сумма");
КонецЦикла;
// Теперь мы можем сгруппировать данные так же быстро, как в запросе
ТабДанных.Сгруппировать("Документ", "Сумма");
Важный момент: чтобы не переписывать алгоритм вывода отчета, который завязан на обход группировок запроса, мы можем эмулировать поведение запроса, перебирая строки ИТЗ методами ВыбратьСтроки() и ПолучитьСтроку().
Для баз данных, работающих на SQL Server, наиболее эффективным методом является использование прямых запросов (компонента 1С++). Посмотрим на пример ситуации: когда документов в списке более 10 000, штатные методы становятся нежизнеспособными.
В прямом запросе мы можем передать список идентификаторов документов (IDDOC) непосредственно в SQL-инструкцию WHERE ... IN (...). Однако, стоит помнить, что SQL имеет ограничения на длину строки запроса. Рассмотрим более надежный способ — использование временных таблиц.
IDDOC из нашего списка.JOIN (соединение) основной таблицы журнала документов (_1SJOURN) с этой временной таблицей.Такой подход позволяет SQL-серверу использовать индексы по полю IDDOC, благодаря чему данные возвращаются практически мгновенно.
Иногда самым быстрым способом оказывается простой перебор списка с получением объекта. Выясним причину: запрос в 1С 7.7 при каждом обращении к реквизиту документа может инициировать чтение из базы. Если мы работаем напрямую со списком уже известных нам документов, метод ПолучитьДокумент() или прямое обращение к реквизитам через точку может отработать быстрее, чем формирование и выполнение сложного запроса с множеством условий.
Резюме:
Для ускорения работы в 1С 7.7 при наличии готового списка документов мы рекомендуем:
_1SJOURN), обращаясь к ним напрямую через выборку, если это возможно.