При разработке отчетов и обработок в 1С часто возникает ситуация, когда запрос к регистру бухгалтерии (например, ЕПСБУ или Хозрасчетный) начинает выполняться крайне медленно. Особенную сложность представляют запросы, в которых происходит соединение справочников с виртуальными таблицами остатков или движений по полям субконто. Проанализируем типичную ситуацию: запрос к справочнику ОсновныеСредства с получением остатков и оборотов по конкретному объекту выполняется долго, но стоит убрать соединение с таблицей ДвиженияССубконто, как скорость нормализуется. Выясним причину этой проблемы и разберем по шагам, как оптимизировать такой запрос.
Основная причина низкой производительности кроется в механизме работы составных типов данных на уровне SQL-сервера. Поле Субконто в регистре бухгалтерии может содержать десятки различных типов (справочники, документы). Когда мы пишем условие ПО ОсновныеСредства.Ссылка = ЕПСБУДвиженияССубконто.СубконтоДт2, платформа 1С генерирует SQL-запрос, который содержит LEFT JOIN со всеми таблицами, входящими в составной тип этого субконто. Если типов 60 и более, SQL-сервер вынужден строить план запроса с огромным количеством соединений, что перегружает оптимизатор и приводит к выбору неэффективной стратегии выполнения (например, сканированию индекса вместо поиска).
Вторая причина — использование соединения виртуальной таблицы с физической в одном запросе. Это считается "антипаттерном" в 1С, так как планировщик SQL не всегда может корректно оценить количество строк, которое вернет виртуальная таблица, и выбирает неверный алгоритм соединения (Nested Loops вместо Hash Match), что замедляет работу в сотни раз.
Первое, что мы должны сделать — это отказаться от фильтрации в секции ГДЕ или в условии соединения ПО. Все отборы по конкретным значениям должны передаваться напрямую в параметры виртуальной таблицы. Рассмотрим, как изменить исходный код.
Вместо такого соединения:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.ЕПСБУ.Остатки КАК ЕПСБУОстатки
ПО ОсновныеСредства.Ссылка = ЕПСБУОстатки.Субконто2
Мы должны использовать параметры виртуальной таблицы:
РегистрБухгалтерии.ЕПСБУ.Остатки(&Период, , &МассивВидовСубконто, Субконто2 = &Объект)
Важный нюанс: В параметрах виртуальных таблиц регистра бухгалтерии (Остатки, Обороты) есть два способа фильтрации. Параметр Субконто (куда передается массив видов субконто) ограничивает выборку только теми счетами, где данное субконто определено. Параметр Условие накладывает фильтр по конкретной ссылке. Для максимального ускорения рекомендуется использовать оба механизма.
Чтобы "подсказать" SQL-серверу, с какой именно таблицей нужно соединяться, и отсечь лишние 60 типов данных, необходимо использовать функцию ВЫРАЗИТЬ. Это заставит систему игнорировать все таблицы составного типа, кроме указанной.
Проанализируем пример использования в условии виртуальной таблицы:
ВЫБРАТЬ ...
ИЗ РегистрБухгалтерии.ЕПСБУ.ДвиженияССубконто(&НачалоПериода, &КонецПериода, ,
ВЫРАЗИТЬ(СубконтоДт2 КАК Справочник.ОсновныеСредства) = &Объект)
Это сокращает количество внутренних соединений на уровне SQL в десятки раз, позволяя оптимизатору построить корректный план запроса.
Разберем самый надежный способ оптимизации — использование временных таблиц. Рассмотрим структуру правильного пакетного запроса:
1. Помещаем целевой объект во временную таблицу:
Даже если нам нужно получить данные по одному объекту, помещение его во временную таблицу помогает платформе лучше подготовить план последующих соединений.
ВЫБРАТЬ
&Объект КАК ОС
ПОМЕСТИТЬ ВТ_Объект
;
2. Получаем данные из регистра во вторую временную таблицу:
Обращаемся к виртуальным таблицам регистра, используя фильтры по значению из первой временной таблицы. Не забываем про типизацию через ВЫРАЗИТЬ.
ВЫБРАТЬ
ЕПСБУОстатки.КоличествоОстаток,
ЕПСБУОстатки.Субконто2 КАК ОС
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
РегистрБухгалтерии.ЕПСБУ.Остатки(&Период, , ,
Субконто2 В (ВЫБРАТЬ ОС ИЗ ВТ_Объект)) КАК ЕПСБУОстатки
;
3. Финальное объединение:
В последнем пакете соединяем справочник ОС с подготовленными временными таблицами. Это гарантирует, что тяжелые виртуальные таблицы будут рассчитаны отдельно и максимально быстро.
Нужно учитывать, что порядок субконто на счете (1-е, 2-е или 3-е) имеет критическое значение. Индексы в регистре бухгалтерии строятся по принципу: Период + Счет + Субконто1 + Субконто2 + ....
Если Основные средства являются вторым субконто, а в запросе не указан фильтр по первому (например, по Центру материальной ответственности), SQL-сервер может не использовать индекс эффективно. В таких случаях желательно:
Проанализируем таблицу ДвиженияССубконто. Она является самой "тяжелой", так как физически не существует в базе данных и собирается "на лету" из основной таблицы движений и таблицы значений субконто. Если запрос все равно работает медленно, рассмотрим альтернативу: выборку данных напрямую из основной таблицы регистра (РегистрБухгалтерии.ЕПСБУ), где поля СубконтоДт1, СубконтоДт2 доступны без дополнительных соединений, но имеют тип Характеристика.ВидыСубконто.... Работа с ними через ВЫРАЗИТЬ в физической таблице часто оказывается быстрее, чем использование виртуальной таблицы ДвиженияССубконто.
&Объект должен быть внутри скобок).