1с запрос параметр через точку
ВЫБРАТЬ
ЗаказыКлиентовОстатки.Номенклатура.Артикул ,
ЗаказыКлиентовОстатки.ЗаказаноОстаток
ИЗ
РегистрНакопления.ЗаказыКлиентов.Остатки КАК ЗаказыКлиентовОстатки
Приведет к неявному соединению с таблицей справочника Номенклатура, а реальный запрос, который будет выполняться к базе будет аналогичен этому:
ВЫБРАТЬ
СпрНоменклатура.Артикул ,
ЗаказыКлиентовОстатки.ЗаказаноОстаток
ИЗ
РегистрНакопления.ЗаказыКлиентов.Остатки КАК ЗаказыКлиентовОстатки
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
ПО ЗаказыКлиентовОстатки.Номенклатура = СпрНоменклатура.Ссылка
На первый взгляд все корректно и правильно, но как система поведет себя, когда разыменовывается поле составного типа? Система будет соединяться СО ВСЕМИ таблицами, входящими в составной тип! Т.е. запрос
ВЫБРАТЬ
ЦеныНоменклатурыПоставщиков.Регистратор.Номер ,
ЦеныНоменклатурыПоставщиков.Цена
ИЗ
РегистрСведений.ЦеныНоменклатурыПоставщиков КАК ЦеныНоменклатурыПоставщиков
будет преобразован во что-то вроде:
И ко всей этой конструкции будут добавлены ограничения на уровне записей (RLS), если они используются. Все это может существенно замедлить выполнение запроса.
Иногда при написании запроса известно какая ссылка будет находиться в поле составного типа. В этом случае правильно привести составной тип к одному необходимому и избежать соединения со всеми таблицами составного типа. Для приведения составного типа к какому-то одному используется оператор
Параметр <Выражение> можно привести к ссылочному типу или к одному из примитивных типов.
Если <Выражение> содержит в составном типе требуемый <Тип значения> , то приведение типа считается осуществимым, и для каждого значения указанного типа результатом будет это самое значение. Для значений других типов результатом приведения типа будет значение NULL.
Если <Выражение> не содержит в составном типе требуемый <Тип значения> , то выполнение данного запроса завершится ошибкой.
Пример использования оператора Выразить, когда известно какая ссылка будет находиться в поле составного типа:
ВЫБРАТЬ
ВЫРАЗИТЬ (ЦеныНоменклатурыПоставщиков.Регистратор КАК Документ.ЗаказПоставщику).Номер КАК Номер,
ЦеныНоменклатурыПоставщиков.Цена
ИЗ
РегистрСведений.ЦеныНоменклатурыПоставщиков КАК ЦеныНоменклатурыПоставщиков
ГДЕ
ЦеныНоменклатурыПоставщиков.Регистратор ССЫЛКА Документ.ЗаказПоставщику
В запросе выше пожертвовали компактностью получения поля Номер ради производительности. В результате текст запроса получился более громоздким, но запрос выполнится быстрее за счет того, что не будет лишних ненужных соединений со всеми таблицами составного поля Регистратор.
Остались вопросы?
Спросите в комментариях к статье.
На днях писал запрос и наткнулся на интересную особенность при использовании параметров. Если передать параметры ссылочных типов, то к ним можно обращаться как к объектам конфигурации - через оператор "точка". Например: нам необходимо выбрать документы "исполнительные листы" по какой-либо организации. Причем если в качестве параметра передается организация с кодом "01", нам нужно выбрать документы относящееся к организациям с кодами "01", "02", "03", иначе выбрать документы по переданной организации:
В этом запросе мы обращаемся к параметру ссылочного типа "&Организация", мы можем извлечь из этого параметра любую информацию, например: наименование (&Организация.Наименование) или ИНН (&Организация.ИНН), словом все те реквизиты, которые есть в справочнике "Организации". При попытке открыть этот запрос в конструкторе запросов будет выдаваться ошибка, т.к. конструктор считает, что к параметру нельзя так обращаться, но на самом деле запрос РАБОТАЕТ!
Специальные предложения
А не легче ли пользоваться левым соединением, чем писать нечитаемые запросы ?
Ну или
(11) 7OH, Какова судьба параметра &другаяОрганизация ?
Еще пример: есть справочник, у него в реквизитах хранятся 2 даты - начало и конец периода (за который предполагается провести некую оценку). Так вот предложенный в (8) приём позволит передать всего один параметр, и спокойно работать с его реквизитами.
Использование лишней временной таблицы, соединение, и все сопутствующие навороты навряд ли добавит читаемости запросу, и, сдается мне, негативно скажется на времени выполнения запроса.
А по поводу Вашего "ну или": в (0) вопрос ставился именно о том, чтобы передавать параметр и обращаться к его реквизитам. В (8) было предложено как при этом сделать запрос пригодным для редактирования конструктором (да и на глаз он сильно страдает). В предложенном Вами варианте нет обращения к реквизитам параметра. В чем "дополнительная возможность использования параметра"? В варианте с "левым соединением" аналогично не будет обращения к реквизитам параметра, да еще и усложнение запроса убавит его читаемости и добавит узких мест (в том смысле, что на лишнем соединении больше шансов накосячить). Кстати: если в том месте, где появится это самое "лишнее" соединение и без того уже есть соединение (нужное, не лишнее), то вероятность накосячить в соединениях многократно возрастает. А обращение к реквизитам параметра позволит спокойно описать все нужные условия или связи.
Хотя могу и заступиться за Ваш способ с соединением: реквизиты параметра (из которого получается таблица из целой одной записи) доступны конструктором. При простом обращении к реквизитам параметра придется писать реквизиты руками, а конструктор будет лишь ругаться, что не нашел такого при неправильном написании, не предлагая правильных вариантов.
Часто при внедрении программ «1С: Предприятие 8» возникают ситуации, в которых простые запросы работают достаточно медленно.
Покажем варианты оптимизации таких запросов.
Для примера рассмотрим запрос из реального проекта (в базе клиента он выполнялся более 6 секунд)
МЕСЯЦ(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Месяц,
ГОД(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Год,
СУММА(ДенежныеСредстваКПоступлениюБезналичныеОбороты.СуммаПриход) КАК СуммаПриход
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(, , Месяц, Документ.Контрагент.Партнер = &Партнер)
C первого взгляда все хорошо, но опытный программист увидит неоптимальный код в запросе.
Источником проблем выступает параметр виртуальной таблицы, а точнее – обращение через «две точки» в фильтре .
В общем случае такой подход допустим, но есть одна проблема: поле «Документ» имеет составной тип, и при получении реквизитов данного поля выполняется соединение с каждой таблицей, входящей в составной тип этого поля .
Самым первым вариантом решения в голову приходит использовать конструкцию языка запросов «ВЫРАЗИТЬ», чтобы привести поле «Документ» к некоторому определенному типу. Это позволит избежать соединений с лишними таблицами. Но по ряду ограничений данный вариант не подходит:
- Нам нужны все документы, содержащиеся в составном типе. Таковы условия постановки задачи. Получается, что необходимо фильтровать все типы документов, входящие в составной тип.
- Даже если бы не было предыдущего ограничения, то обращение через «две точки» никуда не делось.
- Если бы можно было использовать «ВЫРАЗИТЬ», то это не спасало бы ситуацию: в параметрах виртуальной таблицы «ВЫРАЗИТЬ» не дает прироста производительности.
Оптимизация
Исходя из вышесказанного, прежде всего необходимо избавиться от обращения через «две точки» и при этом не испортить саму логику нашего запроса.
Из нескольких способов решения задачи предлагаем два следующих варианта:
Вариант 1
В регистр «ДенежныеСредстваКПоступлениюБезналичные» добавить новое измерение «Партнер», заполняя его при записи движений документов. Ввиду использования условия по данному измерению его необходимо проиндексировать.
После внесенных нами изменений у нас достаточно легко получится наложение фильтра на новое измерение в параметрах виртуальной таблицы:
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(, , Месяц, Партнер = &Партнер) КАК
Что мы видим? Этот запрос начинает работать моментально. И это, к сожалению, единственный положительный момент, минусов наблюдается существенно больше. Главный минус – изменение структуры конфигурации, возникают проблемы при последующих обновлениях, использовании типовых обменов и т.д. К тому же у нас хранится дублируемая информация, что приводит к увеличению размера таблицы, а установка признака индексирования повышает скорость чтения, но при этом замедляет запись в регистр. Поэтому рассмотрим второй вариант.
Вариант 2
Можно попробовать изменить запрос так, чтобы фильтр по полю «Документ» накладывался примерно следующим образом:
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(, , Месяц, Документ В (ВЫБРАТЬ Ссылка ИЗ
ВТ_ДокументыСПартнером)) КАК ДенежныеСредстваКПоступлениюБезналичныеОбороты
Что необходимо сделать, чтобы наш запрос пришел к подобному виду? Вначале соберем все документы, входящие в составной тип поля «Документы». Для них должно соблюдаться условие:
В нашем составном типе определены 5 документов, причем искомый реквизит «Контрагент» присутствует только в документах:
- ПоступлениеБезналичныхДенежныхСредств
- СписаниеБезналичныхДенежныхСредств
- РасходныйКассовыйОрдер
- ОперацияПоПлатежнойКарте
Далее сформируем временную таблицу для фильтрации. В ней будут документы, у которых реквизит «Партнер» равен нужному значению. Применим полученный фильтр по документам в нашем запросе:
ИЗ Документ.ОперацияПоПлатежнойКарте КАК ОперацияПоПлатежнойКарте
ГДЕ ОперацияПоПлатежнойКарте.Контрагент.Партнер = &Партнер
ИЗ Документ.ПоступлениеБезналичныхДенежныхСредств КАК ПоступлениеБезналичныхДенежныхСредств
ГДЕ ПоступлениеБезналичныхДенежныхСредств.Контрагент.Партнер = &Партнер
ИЗ Документ.РасходныйКассовыйОрдер КАК РасходныйКассовыйОрдер
ГДЕ РасходныйКассовыйОрдер.Контрагент.Партнер = &Партнер
ИЗ Документ.СписаниеБезналичныхДенежныхСредств КАК СписаниеБезналичныхДенежныхСредств
ГДЕ СписаниеБезналичныхДенежныхСредств.Контрагент.Партнер = &Партнер
МЕСЯЦ(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Месяц,
ГОД(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Год,
ДенежныеСредстваКПоступлениюБезналичныеОбороты.СуммаПриход КАК СуммаПриход
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(,, Месяц, Документ В
ВТ_ДокументыСПартнером)) КАК ДенежныеСредстваКПоступлениюБезналичныеОбороты
С другой стороны, можно сначала получить контрагентов с данным партнером и затем искать документы с фильтром по контрагенту, но особой разницы в скорости не наблюдается.
После проведенной оптимизации запрос стал выполняться менее одной секунды! Да, при этом он стал сложнее, но нет необходимости в изменении структуры метаданных, как в первом варианте.
Резюме
Вам представлен вариант решения оптимизации достаточно простого запроса, при котором не возникло необходимости в перестройке метаданных, создании дополнительных индексов.
Рекомендуем оптимизировать запросы посредством изменения текста самого запроса.
Анализ плана выполнения запроса с помощью консоли запросов
В этом видео показан наиболее простой способ получения плана выполнения запроса на СУБД – для этого используется официальная консоль запросов от фирмы «1С».
С помощью этого инструмента можно быстро оценить эффективность выполнения запроса и необходимость его оптимизации.
Получение полей через "точку" в запросе
В тестовой конфигурации, в которой будетм реализовывать все примеры в статье, создадим документ "Продажа" и три справочника: "Номенклатура", "ЕдиницыИзмерения" и "БазовыеЕдиницы". Справочник "ЕдиницыИзмерения" подчинен справочнику "Номенклатура". В документе продажи три реквизита: "Номенклатура", "ЕдиницаИзмерения" и "Количество". Первые два ссылаются на элемент соответствующего справочника, "Количество" - числовое поле.
Чтобы проанализировать действия платформы напишем два простых запроса. Первый запрос будет производить выборку ссылки, а также поля "Номенклатура" и "ЕдиницаИзмерения" из документа "Продажи":
Второй запрос будет использовать возможности платформы для выборки полей через "точку" в запросе. Чтобы усложнить пример, сделаем выборку в несколько уровней. В качестве результатирующих полей выборки сделаем ссылку на документ и следующие поля: "Номенклатура", "ЕдиницаИзмерения", "БазоваяЕдиница", "НаименованиеБазовойЕдиницы", "КодБазовойЕдиницы". Текст запроса будет выглядить слеюущим образом:
Результаты выполнения обоих запросов в соответствии с тестовыми данными выглядят следующим образом:
Как мы видим, оба запроса отлично работают. Теперь рассмотрим поведение платформы 1С:Предприятие 8.x, а именно формирование SQL-запроса к СУБД при использовании обращения к полям через "точку" в запросе.
Что делает платформа?
При выполнении первого запроса, 1С:Предприятие формирует достаточно простой SQL-запрос:
В запросе все необходимые данные получаются из одного запроса, поэтому нет необходимости формировать выборки из других таблиц. Если же мы взгяленм на сформированный SQL-запрос для второго примера, картина будет совсем иной:
Как мы видим из приведенного выше текста запроса, каждое обращение через точку в запросе 1С:Предприятия платформа определяет как левое соединение к соответствующей таблице. При этом, если обращение через точку к полям таблицы осуществляется для нескольких полей, то левое соединение выполняется только один раз (что логично). В качестве условий для соединения таблиц используются сравнения по ссылкам.
Плюсы и минусы
Возможности платформы 1С:Предприятия 8.x по построению выборки в запросах через "точку" позволяют упростить построение запросов к базе данных для разработчиков, причем весьма значительно. Согласитель, легче написать в тексте поле через точку от ссылочного типа, чем добавлять, хоть и конструктором, новую таблицу в запрос и прописывать условия соединения. К тому же, это возможность позволяет значительно расширить возможности при настройке отчетов, выводимых полей и прочего. В этом и заключается огромный плюс.
Но есть и другая сторона. Избыточное использование подобной возможности в запросах может значительно повысить нагрузку на сервер СУБД. Все будет зависеть от конкретного запроса. Можно лишь сказать, что нужно стремиться получать выборки данных более оптимальным образом из меньшего количества таблиц.
Небольшой итог
Подведем небольшой итог. Во-первых, использование обращений через "точку" в запросе обрабатываются более оптимально, чем подобные обращения для объектной модели работы с данными. Ранее я писал об этом в одной из статей . Во-вторых, использование подобной возможности значительно ускоряет процесс написания запросов и расширяет возможности настройки отчетов в пользовательском режиме.
При умелом обращении с данным механизмом отрицательное влияние на производительность будет сводиться к нулю. Поэтому не использовать его будет просто не рациональным шагом.
По ссылке Вы можете скачать конфигурацию со всеми примерами из статьи.
Читайте также: