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

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При работе с большими базами данных в 1С:Предприятие 7.7 (в нашем случае база объемом 50 Гб на SQL Server) стандартные механизмы запросов часто начинают работать неудовлетворительно медленно. Одной из типичных задач является поиск всех документов определенного вида (например, УстановкаЦен), в табличной части которых присутствует конкретная номенклатурная позиция. Рассмотрим подробно, как можно оптимизировать этот процесс, начиная от простых правок кода и заканчивая переходом на прямые SQL-запросы.

Метод 1. Оптимизация штатного «черного» запроса

Первое, что мы можем сделать, не меняя архитектуру системы — это проанализировать текущий код запроса. Разберем типичную ошибку вызова функций внутри текста условия. Проанализируем пример кода:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|ОбрабатыватьДокументы Все;
|Обрабатывать НеПомеченныеНаУдаление;
|ТекДок = Документ.УстановкаЦен.ТекущийДокумент;
|Товар = Документ.УстановкаЦен.Номенклатура;    
|Группировка ТекДок;
|Условие (Товар = ТекущийЭлемент());
|";

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


МойТовар = ТекущийЭлемент(); // Вычисляем один раз
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|ОбрабатыватьДокументы Все;
|Обрабатывать НеПомеченныеНаУдаление;
|ТекДок = Документ.УстановкаЦен.ТекущийДокумент;
|Товар = Документ.УстановкаЦен.Номенклатура;    
|Группировка ТекДок;
|Условие (Товар = МойТовар);
|";

Важное примечание: при использовании переменной в условии, SQL-версия 1С 7.7 может более эффективно построить план запроса, так как значение становится константой для движка базы данных.

Метод 2. Использование механизмов «Графы отбора»

Выясним причину, по которой поиск по табличной части документа в 1С 7.7 работает медленно. В SQL-базе данные табличных частей хранятся в таблицах DT*. Эти таблицы имеют индексы только по IDDOC (ссылка на документ) и LINENO (номер строки). Индекса по полю Номенклатура (в SQL это реквизит с именем типа SP*) в этой таблице нет. Следовательно, запрос выполняет полное сканирование (Table Scan) всех строк документов, что на базе в 50 Гб крайне долго.

Чтобы ускорить штатный поиск, мы можем использовать Графы отбора. Разберем по шагам, как это работает:

  1. Откроем Конфигуратор.
  2. Перейдем в ветку «Общие» — «Графы отбора».
  3. Создадим новую графу, например, «ПоискПоНоменклатуре».
  4. В списке «Состав» выберем документ УстановкаЦен и отметим галочкой реквизит табличной части Номенклатура.

После сохранения конфигурации 1С создаст в SQL-базе специальную индексированную таблицу _1SCRDOC. Теперь поиск через метод ВыбратьПоРеквизиту или использование этой графы в запросе будет происходить мгновенно, так как система будет обращаться к индексу, а не перебирать все документы.

Метод 3. Прямые SQL-запросы через 1С++

Если штатных средств недостаточно или вы хотите добиться максимальной производительности, следует использовать внешнюю компоненту 1С++. Прямые запросы позволяют избежать создания временных DBF-файлов (которые 1С 7.7 создает даже в SQL-версии для обработки результатов запроса) и обращаются к данным напрямую.

Рассмотрим пример простого прямого запроса для получения списка документов по товару:


ТекстЗапроса = "
|SELECT 
|    Док.IDDOC [Док $Документ.УстановкаЦен] 
|FROM 
|    $ДокументСтроки.УстановкаЦен AS Док
|WHERE 
|    $Док.Номенклатура = :Товар
|";
рс = СоздатьОбъект("ODBCRecordset");
рс.УстановитьТекстовыйПараметр("Товар", ТекущийЭлемент());
ТЗ = рс.ВыполнитьИнструкцию(ТекстЗапроса);

Однако этот запрос все еще будет выполнять сканирование таблицы строк. Чтобы сделать его по-настоящему быстрым, объединим его с журналом документов и добавим фильтры. Проанализируем более продвинутый пример:


ТекстЗапроса = "
|SELECT 
|    Жур.IDDOC [Док $Документ.УстановкаЦен],
|    Жур.IDDOCDEF [Док_вид]
|FROM 
|    _1SJOURN AS Жур (NOLOCK)
|INNER JOIN 
|    $ДокументСтроки.УстановкаЦен AS Док (NOLOCK) ON Док.IDDOC = Жур.IDDOC
|WHERE 
|    $Док.Номенклатура = :Товар
|    AND Жур.ISMARK = 0 -- Не помеченные на удаление
|    AND Жур.CLOSED > 0 -- Только проведенные (если нужно)
|";

Преимущества данного подхода:

Метод 4. Поиск через историю периодических реквизитов

Посмотрим на ситуацию под другим углом. Если документ УстановкаЦен при проведении меняет периодический реквизит «Цена» в справочнике Номенклатура, то информация об этом уже записана в таблицу констант (периодических реквизитов) _1SCONST.

Выясним, как получить документ через объект Периодический. Это может быть быстрее любого запроса к документам, так как таблица _1SCONST жестко индексирована по объектам (номенклатуре).


Пер = СоздатьОбъект("Периодический");
Пер.ИспользоватьОбъект("Цена", ТекущийЭлемент());
Пер.ВыбратьЗначения(ДатаНачала, ДатаКонца);
Пока Пер.ПолучитьЗначение() = 1 Цикл
    Док = Пер.ТекущийДокумент();
    // Обработка документа
КонецЦикла;

Или, если мы используем 1С++, мы можем обратиться к этой таблице напрямую через SQL. Это особенно полезно, если нам нужно найти только последний документ, установивший цену:


|SELECT TOP 1
|    const.DOCID [Док $Документ]
|FROM 
|    _1SCONST const (NOLOCK)
|WHERE 
|    const.ID = $ИсторияРеквизита.Номенклатура.Цена
|    AND const.OBJID = :ВыбТовар
|ORDER BY 
|    const.DATE DESC, const.TIME DESC, const.DOCID DESC

Заключение и рекомендации

Для ускорения поиска документов в 1С 7.7 на больших SQL-базах мы рекомендуем придерживаться следующей стратегии:

  1. Если база небольшая и изменения нужны минимальные: вынесите условия в переменные перед текстом запроса.
  2. Если вы не хотите использовать сторонние компоненты: настройте Графы отбора для нужных реквизитов табличных частей. Это «золотой стандарт» ускорения штатных механизмов 7.7.
  3. Для профессиональной разработки на SQL-версии: освойте 1С++ и прямые запросы. Это даст прирост скорости в десятки и сотни раз на тяжелых отчетах.
  4. Если важна только актуальная цена: используйте выборку через объект Периодический или таблицу _1SCONST, так как это самый короткий путь к данным в обход тяжелых таблиц документов.

Помните, что на базах объемом 50 Гб и выше, профилактика индексов и обновление статистики в SQL Server являются обязательными условиями быстродействия любого из перечисленных методов.

← На главную