Как ускорить выполнение запроса к регистру накопления при использовании составных типов?

Программист 1С v8.3 (Обычные формы) Управленческий учет IT и автоматизация бизнеса
← На главную

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

Проанализируем исходную ситуацию

Рассмотрим запрос, который вызвал затруднения. Автор использует виртуальную таблицу ОстаткиИОбороты регистра накопления ОборотноСальдовая. Основные проблемы здесь кроются не только в самой таблице, но и в том, как извлекаются данные из ссылочных полей. В частности, использование конструкции ОборотноСальдоваяОстаткиИОбороты.Документ.Дата и Документ.Коментарий для измерения Документ с составным типом данных — это прямой путь к деградации производительности.

Давайте разберем основные причины медленной работы по шагам и выясним, какие инструменты платформы 1С помогут нам исправить ситуацию.

Выбор правильной виртуальной таблицы

Первое, на что стоит обратить внимание — это выбор виртуальной таблицы. В исходном запросе используется ОстаткиИОбороты. Проанализируем ситуацию: если нам нужны только поля СумаРасход и СумаПриход, использование таблицы остатков и оборотов является избыточным. Эта таблица самая «тяжелая» для СУБД, так как платформа 1С вынуждена рассчитывать итоги на начало периода, итоги на конец и обороты между ними.

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

Устранение проблемы «точки» при составных типах

Самое «узкое место» в подобных запросах — это обращение через точку к реквизитам поля, имеющего составной тип. Поле Документ в регистрах часто включает в себя десятки видов документов. Когда мы пишем Документ.Дата, платформа 1С на уровне SQL-запроса выполняет LEFT JOIN (левое соединение) со всеми таблицами документов, входящими в этот составной тип.

Если в типе Документ перечислено 50 видов документов, SQL-сервер объединит 50 таблиц, чтобы найти дату для каждой строки. Это колоссально увеличивает план запроса и время его выполнения. Рассмотрим, как это можно оптимизировать.

Один из способов — использование функции ВЫРАЗИТЬ. Она ограничивает количество соединяемых таблиц только теми, которые вы указали. Посмотрим на пример кода:


ВЫБОР 
    КОГДА ОборотноСальдовая.Документ ССЫЛКА Документ.Начисление 
        ТОГДА ВЫРАЗИТЬ(ОборотноСальдовая.Документ КАК Документ.Начисление).Дата
    КОГДА ОборотноСальдовая.Документ ССЫЛКА Документ.ОплатаБанк 
        ТОГДА ВЫРАЗИТЬ(ОборотноСальдовая.Документ КАК Документ.ОплатаБанк).Дата
    ИНАЧЕ ОборотноСальдовая.Период
КОНЕЦ КАК ДатаДокумента

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

Использование физической таблицы регистра

Если запрос должен возвращать детальные записи по каждому документу, часто быстрее работает обращение к физической таблице регистра накопления (например, РегистрНакопления.ОборотноСальдовая), а не к виртуальной. Виртуальные таблицы хороши для получения агрегатов (сумм), но для листинга движений прямая выборка из физической таблицы с фильтром по периоду и контрагенту работает эффективнее.

Проанализируем ситуацию с индексами. Чтобы фильтр &Контрагент = Контрагент работал быстро, поле Контрагент должно быть измерением и для него должно быть установлено свойство Индексировать. Также важно помнить про поле Активность — при работе с физической таблицей мы должны явно указывать ГДЕ Активность = ИСТИНА.

Рассмотрим пример оптимизированного подхода с использованием временной таблицы:


// Шаг 1: Собираем основные данные во временную таблицу
Запрос.Текст = 
"ВЫБРАТЬ
|   Рег.Сумма КАК Сумма,
|   Рег.ВидДвижения КАК ВидДвижения,
|   Рег.Регистратор КАК Документ,
|   Рег.Период КАК Период
|ПОМЕСТИТЬ ВТ_Движения
|ИЗ
|   РегистрНакопления.ОборотноСальдовая КАК Рег
|ГДЕ
|   Рег.Период МЕЖДУ &Дата1 И &Дата2
|   И Рег.Контрагент = &Контрагент
|   И Рег.Активность = ИСТИНА
|ИНДЕКСИРОВАТЬ ПО
|   Документ;
|
|////////////////////////////////////////////////////////////////////////////////
|// Шаг 2: Выбираем данные и типизируем вид документа
|ВЫБРАТЬ
|   ВТ.Сумма КАК Сумма,
|   ВТ.Документ КАК Документ,
|   ВТ.Период КАК ДатаДокумента,
|   ВЫБОР
|       КОГДА ВТ.Документ ССЫЛКА Документ.Начисление ТОГДА ""Начисление""
|       КОГДА ВТ.Документ ССЫЛКА Документ.ОплатаБанк ТОГДА ""ОплатаБанк""
|       ИНАЧЕ ""Прочее""
|   КОНЕЦ КАК ВидДокумента
|ИЗ
|   ВТ_Движения КАК ВТ";

Оптимизация метода Выгрузить() и получение представлений

В ходе обсуждения на форуме выяснилось, что 70% времени занимает строка Запрос.Выполнить().Выгрузить(). Это очень важный момент. Дело в том, что метод Выгрузить() при обработке ссылочных полей часто пытается автоматически получить представление объекта (строковое имя документа).

Для каждой ссылки в результате платформа может делать скрытый запрос к базе данных, чтобы сформировать строку вида «Расходный кассовый ордер №...». Если в результате 10 000 строк, это превращается в 10 000 микро-запросов. Выясним, как этого избежать:

  1. Используйте функцию ПРЕДСТАВЛЕНИЕ(Поле) прямо в тексте запроса. В этом случае строку сформирует SQL-сервер, и 1С получит уже готовый текст.
  2. Если вы работаете в консоли запросов, время может тратиться на отрисовку данных. Проверяйте реальное время выполнения на сервере через замер производительности.
  3. Вместо Выгрузить() рассмотрите возможность обхода результата выборки через Выбрать() и Следующий(), если вам не нужна таблица значений целиком для передачи в другой интерфейс.

Итоговые рекомендации по ускорению запросов

Подведем итог нашему разбору. Чтобы ваш запрос «летал», придерживайтесь следующих правил:

  1. Выбирайте минимально необходимую таблицу. Нужны только суммы прихода/расхода? Используйте .Обороты. Нужны детальные движения? Пробуйте физическую таблицу регистра.
  2. Минимизируйте использование точек. При работе с составными типами (регистратор, документ) избегайте конструкций Документ.Реквизит. Используйте ВЫРАЗИТЬ или соединение с конкретной таблицей.
  3. Фильтруйте данные максимально рано. Всегда передавайте параметры (период, измерения) в параметры виртуальных таблиц, а не в секцию ГДЕ.
  4. Индексируйте измерения. Проверьте, что те поля, по которым вы накладываете фильтр (например, Контрагент), проиндексированы в метаданных регистра.
  5. Следите за типами. Если вам нужно просто знать название типа документа, используйте ССЫЛКА или ТипЗначения(), не обращаясь к реквизитам объекта.

Применяя эти техники, вы сможете оптимизировать даже самые тяжелые отчеты, снизив нагрузку на сервер и повысив комфорт работы пользователей.

← На главную