В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача получения данных, которые еще не «дошли» до регистров накопления. Типичный пример — отчет по валовой прибыли в ERP, где часть документов реализации (например, товары в пути) отражается в регистре с задержкой, но их данные необходимо включить в отчет уже сейчас по дате самого документа. Рассмотрим, как оптимизировать подобный запрос, если он начинает работать медленно.
В исходной постановке задачи основной «затык» происходил в конструкции НЕ Ссылка В (Выбрать Регистратор ИЗ Обороты). Проанализируем, почему это происходит. При выполнении такого условия СУБД зачастую вынуждена выполнять подзапрос для каждой строки основной таблицы, либо строить неоптимальный план выполнения. Если таблица оборотов содержит тысячи записей, время выполнения растет экспоненциально.
Самым простым и эффективным решением является замена отрицания НЕ В на ЛЕВОЕ СОЕДИНЕНИЕ с последующей проверкой на NULL. Посмотрим на примере, как это выглядит в коде:
// Вместо конструкции ГДЕ НЕ Документ1.Ссылка В (Выбрать Регистратор ИЗ Обороты)
// Используем левое соединение:
ВЫБРАТЬ
Документ1.Ссылка,
Документ1.Количество
ИЗ
ВТ_Документ1 КАК Документ1
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Обороты КАК Обороты
ПО Документ1.Ссылка = Обороты.Регистратор
ГДЕ
Обороты.Регистратор ЕСТЬ NULL
Важный момент: использование ЛЕВОЕ СОЕДИНЕНИЕ ... ГДЕ ... ЕСТЬ NULL позволяет SQL-серверу использовать эффективные алгоритмы соединения (например, Hash Match или Merge Join), что ускоряет выполнение запроса в десятки раз.
Проанализируем использование виртуальной таблицы РегистрНакопления.Регистр.Обороты(,,Регистратор). Когда мы указываем периодичность Регистратор, платформа 1С перестает использовать таблицы итогов (агрегаты) и начинает выбирать данные напрямую из физической таблицы движений регистра. В этом случае виртуальная таблица становится лишь «оберткой» над тяжелым запросом к основной таблице.
Рассмотрим рекомендации по работе с такими таблицами:
Регистратор ССЫЛКА Документ.ВашТип.Регистратор перед дальнейшими соединениями.Выясним причину, по которой использование конструкции ВЫРАЗИТЬ(Обороты.Регистратор КАК Документ.Документ1).Дата МЕЖДУ &ДатаНачала И &ДатаОкончания в блоке ГДЕ является плохой практикой. С точки зрения SQL-сервера, применение функций (включая приведение типов) к полям индекса делает запрос «не-SARGable». Это означает, что индекс по дате документа не может быть использован, и СУБД переходит к полному сканированию таблицы.
Чтобы избежать этой проблемы, выполним оптимизацию следующим образом:
Регистратор.Посмотрим на пример правильной структуры запроса:
// Шаг 1: Подготовка списка документов с фильтром по дате
ВЫБРАТЬ
Документ1.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_НужныеДокументы
ИЗ
Документ.Документ1 КАК Документ1
ГДЕ
Документ1.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
ИНДЕКСИРОВАТЬ ПО
Ссылка;
////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Получение оборотов только по отобранным документам
ВЫБРАТЬ
Регистр.Регистратор,
Регистр.Количество
ИЗ
РегистрНакопления.ВашРегистр КАК Регистр
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_НужныеДокументы КАК НужныеДокументы
ПО Регистр.Регистратор = НужныеДокументы.Ссылка
ГДЕ
Регистр.Активность = ИСТИНА
Для конфигураций на базе ERP 2 и УТ 11 существует специализированный механизм — регистр сведений ДанныеПервичныхДокументов. Посмотрим, почему он может быть полезен. Этот регистр является «плоским» и содержит основные реквизиты всех документов (дату, номер, сумму, ссылку). Обращение к нему происходит значительно быстрее, чем к тяжелым таблицам самих документов (таким как РеализацияТоваровУслуг), которые содержат сотни полей и метаданных.
Если задача стоит в получении списка документов за период для последующей сверки с регистрами, попробуем сначала обратиться к ДанныеПервичныхДокументов.
Проанализируем ситуацию, когда даже оптимизированный запрос начинает работать медленно из-за огромного объема данных. В этом случае стоит задуматься об изменении архитектуры. Если отчет нужен часто, создание дополнительного оборотного регистра может быть оправдано.
Например, для задачи «товары в пути» можно реализовать следующую логику:
ТоварыВПути (приход).LEFT JOIN.Подведем итоги наших изысканий. Для максимально быстрого выполнения запроса придерживайтесь следующей последовательности действий:
Регистратор и Ссылка во временных таблицах должны быть проиндексированы.Документ.Документ1.Товары) заходите только после того, как во временной таблице остался минимально необходимый список ссылок.Применение этих методов позволит сократить время формирования отчета с нескольких минут до долей секунды даже на крупных информационных базах.