- Реквизиты через точку в запросе. как избежать?
- Получение полей через точку от других полей
- Получение поля через точку
- Получение поля Ссылка через точку
- Получение полей через точку от полей, ссылающихся на несколько объектов
- Использование конструкции ВЫРАЗИТЬ для ограничения количества соединений при получении полей через точку
- Оптимизация обращений к реквизитам объектов через точку
- Как в 1С оптимизировать запрос – пример ускорения в 6 раз
- Оптимизация
- Резюме
- Анализ плана выполнения запроса с помощью консоли запросов
- Зачем вообще нужна точка при обращении к реквизитам?
Реквизиты через точку в запросе. как избежать?
(4) Не очень удачный пример.
В нём ВЫРАЗИТЬ нафиг не нужно, т.к. реквизит «Владелец» скорее всего не является составным.
Этот пример показателен с другой стороны. К вопросу о том зачем в документе отдельный реквизит Контрагент, когда есть Договор (контрагента можно получить в виде Владельца этого договора). То есть вроде как налицо явная информационная избыточность. Однако при внимательном рассмотрении выясняется, что этот несчастный контрагент нужен сплошь и рядом при работе с документом, а потому целесообразнее (с точки зрения производительности), когда он хранится в таблице документа в виде отдельного поля, а не получается через соединение от договора.
(0) >> Как получить значение свойства без точки?
(6) любой составной тип делает джойн сначало с таблицей конфигурации (метаданных) и после этого делает джойны ко всем таблицам из по типу вне зависимости от реального типа данных.
при обычных условиях такие расходы не очень велики, но при отсутствии статистики или большого количества мелких запросов (например в динамических списках) это существенно.
(11) >любой составной тип делает джойн сначало с таблицей конфигурации (метаданных)
А подробнее можно? Как это выглядит на уровне SQL? Делать джойны с неизвестными на момент разбора запроса таблицами еще ни одна из поддерживаемых платформой СУБД не научилась. 🙂
Я до сих пор считал, что все метаданные и имена соответствующих таблиц кэшируются при первом обращении и в дальнейшем берутся из памяти.
Получение полей через точку от других полей
В языке запросов реализована возможность получения поля через точку от другого поля. С одной стороны, эта возможность позволяет создавать компактные запросы, однако, с другой стороны, всегда следует понимать, что стоит за каждым таким действием. В данном разделе будет рассказано, что происходит при получении поля через точку, и будут даны рекомендации для оптимизации доступа к полям.
Получение поля через точку
Рассмотрим следующий запрос:
ВЫБРАТЬ
Номенклатура.Наименование,
КоличествоОборот
ИЗ
РегистрНакопления.УчетНоменклатуры.Обороты КАК УчетНоменклатурыОбороты
В этом запросе поле «Наименование» получается через точку от поля «Номенклатура». При исполнении такого запроса язык запросов 1С:Предприятия создаст неявное соединение со справочником «Номенклатура», и будет получать поле «Наименование» из него. Таким образом, реальный запрос, который будет исполняться, будет аналогичен следующему:
ВЫБРАТЬ
СправочникНоменклатура.Наименование,
КоличествоОборот
ИЗ
РегистрНакопления.УчетНоменклатуры.Обороты КАК УчетНоменклатурыОбороты
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СправочникНоменклатура
ПО УчетНоменклатурыОбороты.Номенклатура = СправочникНоменклатура.Ссылка
Следует отметить, что если в запросе происходит получение нескольких полей через точку от одного поля, то соединение с таблицей, на которую ссылаются поля через точку, будет создано одно. Например, если в первом примере мы будем получать не только поле «Наименование», но и поле «Код» через точку от поля «Номенклатура», будет создано одно, а не два соединения с таблицей «Номенклатура».
Получение поля Ссылка через точку
Не следует получать поле «Ссылка» через точку от другого поля. При таком способе получения поля «Ссылка» будет создаваться дополнительное соединение, которое, скорее всего, замедлит выполнение запроса.
Например, в следующем запросе поле «Ссылка» получается через точку от поля «Контрагент»:
ВЫБРАТЬ
РасходнаяНакладная.Дата,
РасходнаяНакладная.Номер
ИЗ
Документ.РасходнаяНакладная КАК РасходнаяНакладная
ГДЕ
РасходнаяНакладная.Контрагент.Ссылка = &Контрагент
В результате будет создано совершенно ненужное в данном случае соединение с таблицей «Контрагенты» и, как следствие, выполнение запроса, скорее всего, замедлится. Такой запрос следует переписать следующим образом:
ВЫБРАТЬ
РасходнаяНакладная.Дата,
РасходнаяНакладная.Номер
ИЗ
Документ.РасходнаяНакладная КАК РасходнаяНакладная
ГДЕ
РасходнаяНакладная.Контрагент = &Контрагент
Получение полей через точку от полей, ссылающихся на несколько объектов
Если поле, через которое получается другое поле, является ссылкой на несколько таблиц, то при выполнении запроса будет осуществлено столько соединений, в скольких ссылаемых таблицах будет найдено требуемое поле.
Пример. Пусть поле «Регистратор» регистра накопления ссылается на два документа: «РасходнаяНакладная» и «ПриходнаяНакладная». В таком случае следующий запрос:
ВЫБРАТЬ
УчетНоменклатуры.Регистратор.Номер,
УчетНоменклатуры.Количество
ИЗ
РегистрНакопления.УчетНоменклатуры КАК УчетНоменклатуры
даст неявное соединение с обеими таблицами документов, то есть будет выполнено два соединения. Исполняемый запрос будет выглядеть приблизительно так:
ВЫБРАТЬ
ВЫБОР
КОГДА УчетНоменклатуры.Регистратор ССЫЛКА Документ.ПриходнаяНакладная
ТОГДА ПриходнаяНакладная.Номер
КОГДА УчетНоменклатуры.Регистратор ССЫЛКА Документ.РасходнаяНакладная
ТОГДА РасходнаяНакладная.Номер
КОНЕЦ,
УчетНоменклатуры.Количество
ИЗ
РегистрНакопления.УчетНоменклатуры КАК УчетНоменклатуры
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
ПО УчетНоменклатуры.Регистратор = ПриходнаяНакладная.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РасходнаяНакладная КАК РасходнаяНакладная
ПО УчетНоменклатуры.Регистратор = РасходнаяНакладная.Ссылка
Если же поле, через которое получается другое поле, является любой ссылкой, то возможны ситуации, при которых будет происходить неявное соединение со всеми объектными таблицами конфигурации. Так, например, если мы получаем от поля типа «любая ссылка» поле «Представление», а в нашей конфигурации присутствует 50 справочников и 100 документов, то будет произведено 150 соединений с различными таблицами.
На это стоит обращать внимание при разработке структуры данных, также об этом следует помнить при составлении запросов.
Использование конструкции ВЫРАЗИТЬ для ограничения количества соединений при получении полей через точку
Иногда, при составлении запроса известно, какая ссылка будет находиться в том или ином поле, ссылающемся на несколько таблиц. В этом случае можно явно указать в запросе нужную таблицу для того, чтобы неявное соединение выполнялось только с указанной таблицей, а не со всеми таблицами, на которые ссылается данное поле.
Пример. Пусть поле «Регистратор» регистра накопления ссылается на два документа: «РасходнаяНакладная» и «ПриходнаяНакладная», и в предложении «ГДЕ» выборка ограничивается только значениями регистратора, ссылающимися на «РасходнуюНакладную»:
ВЫБРАТЬ
УчетНоменклатуры.Регистратор.Номер,
УчетНоменклатуры.Количество
ИЗ
РегистрНакопления.УчетНоменклатуры КАК УчетНоменклатуры
ГДЕ
УчетНоменклатуры.Регистратор ССЫЛКА Документ.РасходнаяНакладная
Так как в данном запросе мы четко знаем, что в результат попадут только документы, у которых регистратор ссылается на таблицу расходных накладных, мы можем несколько доработать запрос для того, чтобы он выполнялся более эффективно:
ВЫБРАТЬ
ВЫРАЗИТЬ(УчетНоменклатуры.Регистратор КАК Документ.РасходнаяНакладная).Номер,
УчетНоменклатуры.Количество
ИЗ
РегистрНакопления.УчетНоменклатуры КАК УчетНоменклатуры
ГДЕ
УчетНоменклатуры.Регистратор ССЫЛКА Документ.РасходнаяНакладная
При исполнении такого запроса будет создано соединение лишь с таблицей «Документ.РасходнаяНакладная», вместо соединения с обеими таблицами, на которые ссылается поле «Регистратор». Это положительно повлияет на скорость выполнения запроса.
Оптимизация обращений к реквизитам объектов через точку
В базе сделана куча проверок, где идет обращение к реквизитам через точку.
Например, Заказ.Договор.Владелец.ИНН
Это съедает скорость работы. Одна проверка через такое обращение занимает 38%.
1) Написание общей функции повторного использования, которая делает обращение к промежуточным данным (чтобы минимизировать вероятность получения устаревших данных). Примерно так:
ПовтИсп.ЗначениеРеквизита(Заказ,»Договор.Владелец»).ИНН
есть еще какие-то варианты?
Долго возможно. Скорость выполнения увеличится точно.
Но есть разные нюансы. Например, если этот код выполняется в цикле, то переписав на запрос можно получить обратный эффект.
В первом будет количество вызовов 2 + 3 + 3 = 8
Во втором количество вызовов 1 + 1 + 1 + 1 + 1 = 5
Здесь на 3 строчках сэкономили 3 вызова. А таких строчек, где переписав код можно получить выигрыш в типовых конфигурациях тысячи. Особенно, хороший выигрыш можно получить когда такой код находится внутри процедур и функций (так как они вызываются многократно), а также внутри циклов.
Это общее правило программирования, которое должно применяться повсеместно, на каком бы языке программирования не писался код и к сожалению это правило многие игнорируют. В результате имеем тормознутые сайты, а в случае с 1С тормознутые конфигурации. Конфигурации тормозят конечно не только из за нарушения этого принципа, тормозов в них и без него хватает, но нарушая основные правила программирования эти тормоза дополнительно усугубляются.
Как в 1С оптимизировать запрос – пример ускорения в 6 раз
Что Вы узнаете из этой статьи?
• Одну из основных причин медленной работы запросов
• Анализ возможных методов ускорения запросов
• Эффективный способ ускорения запросов, в которых происходит обращение через «2 точки»
Часто при внедрении программ «1С: Предприятие 8» возникают ситуации, в которых простые запросы работают достаточно медленно.
Покажем варианты оптимизации таких запросов.
Для примера рассмотрим запрос из реального проекта (в базе клиента он выполнялся более 6 секунд)
МЕСЯЦ(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Месяц,
ГОД(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Год,
СУММА(ДенежныеСредстваКПоступлениюБезналичныеОбороты.СуммаПриход) КАК СуммаПриход
C первого взгляда все хорошо, но опытный программист увидит неоптимальный код в запросе.
Самым первым вариантом решения в голову приходит использовать конструкцию языка запросов «ВЫРАЗИТЬ», чтобы привести поле «Документ» к некоторому определенному типу. Это позволит избежать соединений с лишними таблицами. Но по ряду ограничений данный вариант не подходит:
Оптимизация
Исходя из вышесказанного, прежде всего необходимо избавиться от обращения через «две точки» и при этом не испортить саму логику нашего запроса.
Из нескольких способов решения задачи предлагаем два следующих варианта:
Вариант 1
В регистр «ДенежныеСредстваКПоступлениюБезналичные» добавить новое измерение «Партнер», заполняя его при записи движений документов. Ввиду использования условия по данному измерению его необходимо проиндексировать.
После внесенных нами изменений у нас достаточно легко получится наложение фильтра на новое измерение в параметрах виртуальной таблицы:
Что мы видим? Этот запрос начинает работать моментально. И это, к сожалению, единственный положительный момент, минусов наблюдается существенно больше. Главный минус – изменение структуры конфигурации, возникают проблемы при последующих обновлениях, использовании типовых обменов и т.д. К тому же у нас хранится дублируемая информация, что приводит к увеличению размера таблицы, а установка признака индексирования повышает скорость чтения, но при этом замедляет запись в регистр. Поэтому рассмотрим второй вариант.
Вариант 2
Можно попробовать изменить запрос так, чтобы фильтр по полю «Документ» накладывался примерно следующим образом:
ВТ_ДокументыСПартнером)) КАК ДенежныеСредстваКПоступлениюБезналичныеОбороты
Что необходимо сделать, чтобы наш запрос пришел к подобному виду? Вначале соберем все документы, входящие в составной тип поля «Документы». Для них должно соблюдаться условие:
В нашем составном типе определены 5 документов, причем искомый реквизит «Контрагент» присутствует только в документах:
Далее сформируем временную таблицу для фильтрации. В ней будут документы, у которых реквизит «Партнер» равен нужному значению. Применим полученный фильтр по документам в нашем запросе:
ИЗ Документ.ОперацияПоПлатежнойКарте КАК ОперацияПоПлатежнойКарте
ГДЕ ОперацияПоПлатежнойКарте.Контрагент.Партнер = &Партнер
ИЗ Документ.ПоступлениеБезналичныхДенежныхСредств КАК ПоступлениеБезналичныхДенежныхСредств
ГДЕ ПоступлениеБезналичныхДенежныхСредств.Контрагент.Партнер = &Партнер
ИЗ Документ.РасходныйКассовыйОрдер КАК РасходныйКассовыйОрдер
ГДЕ РасходныйКассовыйОрдер.Контрагент.Партнер = &Партнер
ИЗ Документ.СписаниеБезналичныхДенежныхСредств КАК СписаниеБезналичныхДенежныхСредств
ГДЕ СписаниеБезналичныхДенежныхСредств.Контрагент.Партнер = &Партнер
МЕСЯЦ(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Месяц,
ГОД(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Год,
ДенежныеСредстваКПоступлениюБезналичныеОбороты.СуммаПриход КАК СуммаПриход
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(,, Месяц, Документ В
ВТ_ДокументыСПартнером)) КАК ДенежныеСредстваКПоступлениюБезналичныеОбороты
С другой стороны, можно сначала получить контрагентов с данным партнером и затем искать документы с фильтром по контрагенту, но особой разницы в скорости не наблюдается.
После проведенной оптимизации запрос стал выполняться менее одной секунды! Да, при этом он стал сложнее, но нет необходимости в изменении структуры метаданных, как в первом варианте.
Резюме
Вам представлен вариант решения оптимизации достаточно простого запроса, при котором не возникло необходимости в перестройке метаданных, создании дополнительных индексов.
Рекомендуем оптимизировать запросы посредством изменения текста самого запроса.
Анализ плана выполнения запроса с помощью консоли запросов
В этом видео показан наиболее простой способ получения плана выполнения запроса на СУБД – для этого используется официальная консоль запросов от фирмы «1С».
С помощью этого инструмента можно быстро оценить эффективность выполнения запроса и необходимость его оптимизации.
Бурмистров Андрей
Другие полезные статьи и видео смотрите на нашем сайте: http://
Зачем вообще нужна точка при обращении к реквизитам?
>Если конфа точно не будет под нагрузкой? Если лень писать запрос?
Наверное, примерно так.
(5) Во-вторых, это повышает скорость разработки и снижает затраты на сопровождение кода.
(0) Ошибка проектирования. Не заложили достаточно гибкости. Если хотя бы ТЧ и ЧЗ всякие не тянулись бы безусловно, уже было бы терпимо.
>почему 1С не поменяет механизм работы точки?
Поздно уже. Груз легаси кода неподъёмен.
(6) В других давно пришли к парадигме CQRS.
(0) > И самое главное, почему 1С не поменяет механизм работы точки?
потому что всякие нубы не обладают пониманием того что точка это мета-конструкция которая позволяет писать коротко.
(26) > Да пусть «внутренний запрос» хоть четырежды скомпилирован.
ну дык это разрабу решать, каким образом оформлять алгоритм. есть 2 пути: запрос и через точку, разраб сам и выбирает.
не скрою, тоже думал об этом, что иногда получаем избыточный набор реквизитов объекта. И как бы я программировал «экономичные выборки». Типа:
и мы влипаем в след. колизию: для «усеченного» объекта пришлось бы хранить в памяти словари усечения, т.е набор обрабатываемых реквизитов, тогда как для «неусеченного» объекта можно тупо использовать сингелтонные словари из метаданных. Это увеличит расход памяти на внутренний объект переменной, а их зачастую десятки тысяч.
Тут разрабам нужно выбирать тщательно.
(39) > Чтобы средний разраб «хорошо решал», ему хорошо бы иметь максимально предсказуемое поведение системы.
т.е. документацию изучить.
(57) Возможное улучшение действительно может заключаться в разрешении частичного кэширования. И возможности указать (как в БСП), какие реквизиты потребуются в дальнейшем.
Но это сильно усложнит реализацию, особенно в части инвалидации кэша. Не факт, что оно того стоит.
(43) А теперь сравни количество 1Сников и количество остальных программистов для бизнес-приложений 😉
(45) Т.е. ты предлагаешь не читать объект? Тогда как будет обеспечиваться синхронность данных, полученных в разные моменты времени? Блокировкой с уровнем изоляции REPEATABLE READ? Вы реально считаете, что это ускорит работу нагруженной системы?
А чего не всю базу сразу? «Непротиворечивость» нужно рассматривать в контексте.
Если бы мы говорили про систему написанную с нуля, тогда бы согласился: от неявного чтения через объектную модель можно вообще отказаться.
(76) >> лучше уж повторный запрос
Не лучше. Если мы говорим про средний объект(без сотен реквизитов и огромных ТЧ), то пара-тройка запросов будет не оптимальней чтения объекта целиком.
(69) Угу, и получить тормоза на ожидании блокировки. типа, хочешь изменить объект. но низззя! потому что его кто-то прочитал, например, для отчета. И так пока или сборщик мусора не уничтожит все ссылки на этот объект, или программист явно не разблокирует объект.
(72) Непротиворечивость для объекта нужна гораздо чаще, чем для базы.
В итоге четыре раза сходил в базу, а объект больше не понадобился. Бред же. Никакой логики.
Сейчас программист сам может решать когда и что читать и как это оптимизировать, а не рассчитывать на оптимизатор, который может не угадать.
А я всегда через точку обращаюсь, что бы было видно от кого эта переменная. Знаю, что это плохо и вредно, но так удобнее)))))
А ещё локальные переменные объявляю вначале процедуры через Перем и вношу описание, для чего и от чего они. Тоже ересь полная, но так удобнее и красивее. Зато минимизируются «зависшие» переменные