Курс по Оптимизации 1С – Занятие №7

В рамках этого занятия необходимо изучить следующие материалы.

Модуль 3. Причины медленной работы

    Глава 8. Анализ причин медленной работы и оптимизация системы

    • Подзапрос в условии соединения
    • Работа с полями состовного типа в запросах
    • Параметры виртуальной таблицы. Запросы в цикле
    • Особенности работы с виртуальными таблицами
    • Рекомендации по написанию запросов

Практическое задание

К сожалению, у Вас недостаточно прав для дальнейшего просмотра.

Если Вы приобрели курс, но еще не активировали токен — пожалуйста, активируйте доступ по инструкциям, высланным на Ваш email после покупки.

Если Вы не залогинены на сайте — залогиньтесь, вернитесь на эту страницу и обновите ее.

Если Вы залогинены, у Вас активирован токен доступа, но Вы все равно видите эту запись — напишите нам на e-mail поддержки.

Комментарии / обсуждение (221):

  1. Иван

    Добрый день.
    Решив все практические задания решил опробовать новые знания на рабочей базе.

    В базе есть рег. сведений “ЦеныНоменклатуры”. Все измерения НЕ составные, ссылочные и ведущие. Записей в регистре 9,2 млн.
    Измерения в порядке их следования: ТипЦен, Номенклатура, КодТовара (справочник, который по сути обозначает номер товара в партии), Характеристики (не используются).
    Никак не удается попасть в индекс при получении среза последних, хотя известны все значения (ТипЦен, Номенклатура, КодТовара).
    Пробовал следующие варианты:
    – передавал параметры в виртуальную таблицу отдельно для каждого измерения
    – собирал все данные в одну таблицу и передавал в параметры в виде структуры “(ТипЦен,Номенклатура,КодТовара) В (ВЫБРАТЬ…)” – эта конструкция работает гораздо медленнее чем предыдущий вариант
    Сейчас остановился на таком варианте:
    – собрал все данные в одну таблицу и соединил ее с физической таблицей с последующей обработкой – выполняется за доли секунды.

    Столкнулся с такой же проблемой в регистре накопления – получаю остатки заполнив все параметры, но плане запросе явно видно что в индекс не попадает полностью (SEEK… WHERE…).
    В этом случае не получится использовать физическую таблицу…

    Как попасть в индекс? Что я делаю не так?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

      • Иван

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

        • Андрей Бурмистров


          (текст комментария доступен только участникам Мастер-группы)

  2. Александр

    Здравствуйте. У меня получился запрос, по которому оптимизатор выбрал Nested loops, в плане запроса видно, что оператор с первой таблицей вернул 0 строк, оператор со второй таблицей не выполнялся ни разу, тем не менее второй оператор имеет стоимость почти в половину всего запроса. Как это объяснить?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  3. Евгений

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

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

      • Евгений

        Андрей, а зачем организацию добавлять во временную таблицу? Она же передается параметром виртуальной.
        Посмотрел планы запросов, они практически идентичны только в одном случаи поиск с отбором по параметру, а во втором с отбором по #tt3._..RRef
        Протестировал запрос ~700 раз +- одинаково.

        И еще вопрос по моим запросом, в планах запросов есть параметр TotalSubtreeCost, как вы говорили он измеряется в “попугаях” а почему в двух планах он очень разный, причем в более быстром запросе он намного больше? параметр TotalSubtreeCost зависит от EstimateRows?

        • Андрей Бурмистров


          (текст комментария доступен только участникам Мастер-группы)

  4. e.martynenko

    Добрый день. Подскажите, что в sql-ном тексте запроса значит оператор WITH(NOLOCK)?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  5. galakt

    Добрый день. Можно посмотреть исходный запрос для задания 8.5? Задание 8 уже решил.

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  6. MakhoninMY

    Задание 8-5. Не является опечаткой то, что дважды выбирается поле T12._Description? Может быть должно быть T11._Description?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  7. Виктор Яковлев

    Здравствуйте. Возник вопрос по заданию 07.

    Является ли нормальной практикой использовать подзапрос в параметрах виртуальной таблицы остатков (Измерение1, Измерение2) В (ВЫБРАТЬ …). Разве в этом случае не будет соединение виртуальной таблицы с подзапросом?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  8. serk@rarus.ru

    Здравствуйте,

    Виртуальную таблицу соединять с физической таблицей – это неоптимальный запрос, А вот виртуальную таблицу с временной таблицей соединять можно? Или лучше делать две временные таблицы, а потом их соединять?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  9. Gosha009

    В задании 8.1 в запросе есть строка | ОстаткиНоменклатурыОстатки.СтрокаЗаказа.ДокументВладелец КАК Заказ.
    Что-то я не пойму какого типа может быть СтрокаЗаказа?. По идее строка заказа -должно содержать примитивный тип с указанием на номер строки ТЧ документа, но в таком случае невозможно обращение через точку к реквизиту ДокументВладелец. Следовательно СтрокаЗаказа это поле ссылочного типа. Неужели имеется в виду справочник с номерами строк, имеющим реквизит ДокументВладелец?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  10. yamarsel

    Я выполнил 2 запроса в системе:
    1) ВЫБРАТЬ ПЕРВЫЕ 1
    РС_Тест1.СоставнойТип
    ИЗ
    РегистрСведений.РС_Тест1 КАК РС_Тест1

    УПОРЯДОЧИТЬ ПО
    СоставнойТип

    2) ВЫБРАТЬ
    МИНИМУМ(РС_Тест1.СоставнойТип) КАК СоставнойТип
    ИЗ
    РегистрСведений.РС_Тест1 КАК РС_Тест1

    В итоге показатель TotalSubtreeCost для первого запроса оказался равен аж 8,5 единицам, в то время как для второго всего 0,95 единицы. Визуально, действительно, первый запрос выполняется дольше.

    Хотя в видеоуроке было сказано обратное.

    В чем интересно тут может быть дело?
    База – та самая, на которой проводится обучение.

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  11. lubavin

    Андрей добрый день!
    Есть ли рекомендации по использованию индекса во временной таблице?
    Ты говорил, что далеко не всегда он будет использован, и зачастую системе легче использовать скан таблицы чем ее индекса.

    А что в случае, если в запросе к ней происходит несколько обращений, как например в Домашнем задании 07, где по ней можно и фильтровать и Таблицу остатков, и таблицу лимитов?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  12. Дмитрий

    Подскажите, пожалуйста, что означает ? в тексте sql запроса, например тут:
    ON ((T4._Fld5616RRef = T5._Reference124_IDRRef) AND (? = T5._Fld2712RRef))

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

      • Дмитрий

        Это как-то зависит от версии платформы или SQL Server? Потому что у меня в профайлере параметры обозначаются как @P1, например.

        • Андрей Бурмистров


          (текст комментария доступен только участникам Мастер-группы)

  13. SpecRam

    Добрый день!
    1. Где я могу взять базу для решения ДЗ?;
    2. Хочу получать уведомления на ответ текущего комментария.

    • Татьяна Гужавина

      Добрый день, Рамиль!
      <1. Где я могу взять базу для решения ДЗ?;
      База для выполнения большинства ДЗ не нужна, для выполнения ДЗ достаточно скринов и текстов запросов которые к ДЗ прилагаются.
      <2. Хочу получать уведомления на ответ текущего комментария.
      Такой функции на данный момент на сайте нет. Но мы работаем над улучшением сайта.

  14. hjkl

    Добрый день.

    В ходе просмотра видео про поля составного типа решил провести следующий эксперимент – написал запрос (см. прикрепленный файл ТекстЗапроса.txt);

    Запрос по формированию временной таблицы приведу в тексте сообщения:

    exec sp_executesql N’INSERT INTO #tt1 (_Q_001_F_000TRef, _Q_001_F_000RRef) SELECT TOP 10
    T1._RecorderTRef,
    T1._RecorderRRef
    FROM _AccumRg18 T1 WITH(NOLOCK)
    WHERE (T1._RecorderTRef = @P1)’,N’@P1 varbinary(4)’,0x0000000C

    Я правильно понял что в такой запрос в СУБД формирует таблицу с двумя колонками? следующего вида:
    RecorderTRef RecorderRRef
    Документ.Продажа Ссылка1
    Документ.Продажа Ссылка2

    Документ.Продажа Ссылка10

    Смущает ситуация из скриншота (см. прикрепленный файл Скриншот.jpg) и текст запроса в терминах СУБД по временной таблице (см. прикрепленный файл ТекстЗапроса.txt) – и как следствие возникает вопрос:

    Хотя на скриншоте в конструкторе запроса видно что поле Регистратор осталось составным, но ведь во временную таблицу попали только регистраторы имеющие тип Документ.Продажа – каким образом получаются левые соединения с таблицами других документов?

      • Андрей Бурмистров


        (текст комментария доступен только участникам Мастер-группы)

        • hjkl

          Значит дело в платформе, а я думал что оптимизатор СУБД окажется умнее.

          Я специально не использовал ВЫРАЗИТЬ при создании временной таблицы – расчет был следующий:

          1) когда в видео 2 модуля вы рассказывали про статистику, то говорилось что например если есть в таблице колонка “номенклатура” то статистика содержит информацию сколько и каких номенклатур содержится в этом столбце.

          2) в каком то видео говорилось что когда создается временная таблица то по ней формируется статистика.

          3) Поскольку благодаря статистике известно что есть только Документ.Продажа оптимизатор догадается, что нужно соединиться только с его таблицей.

          • Андрей Бурмистров


            (текст комментария доступен только участникам Мастер-группы)

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  15. Светлана

    Задание 8-2
    Нет выбора полей из первой таблицы внутреннего соединения “ТаблицаНоменклатуры”. В качестве оптимизации можно поместить «ТаблицаНоменклатуры» во временную таблицу и в параметрах виртуальной таблицы СрезПервых добавить условие на Номенклатуру и Характеристику из этой временной таблицы.
    Я посмотрела, что такое решение предлагают и другие участники. Я правильно понимаю, что это решение будет оптимальнее, так как поиск будет работать быстрее, чем соединение (для данного примера)?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  16. Светлана

    Задание 7. В решении в параметрах виртуальной таблицы идет условие (Склад = &Склад и Номенклатура в (Выбрать ВремТабл.Номенклатура….), а если во ВремТабл добавить колонку “Склад” со значением &Склад и уже в параметрах виртуальной таблицы использовать конструкцию (Склад, Номенклатура) В (Выбрать ВремТабл.Склад, ВремТабл.Номенклатура). Может быть такое решение оптимальнее?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

      • e.sholokh@efsol.ru

        А объясните почему так более оптимально?

        • Андрей Бурмистров


          (текст комментария доступен только участникам Мастер-группы)

  17. lubavin

    Андрей, появился еще вопрос по полям составного типа.
    Справедливо ли, что следует использовать для составного типа ВЫРАЗИТЬ() везде, где ясно какой тип нужен? В нижеприведенном запросе, при формировании временной таблицы, нужно принудительно указывать тип? Считаем что поле ДокументОснование имеет тип нескольких разных документов.

    ВЫБРАТЬ Выразить(Операция.ДокументОснование как Документ.Отгрузка) как Отгрузка
    ПОМЕСТИТЬ ВТ_Отгрузки
    ИЗ
    ……
    ;
    ////
    ВЫБРАТЬ Ссылка из Документ.Отгрузка ГДЕ ССЫЛКА В (Выбрать Отгрузка ИЗ ВТ_Отгрузки)

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  18. Дмитрий Абраменко

    И еще есть вопрос по решению практического задания номер 7:
    1)Почему Вы сначала получили ВТ ВремТаблицаНоменклатураИОстаток на основе соединения Товаров и Остатков, а уже потом соединили ее с таблицей лимитов в отдельном подзапросе, единый запрос с соединением 3х таблиц сразу не оптимален?
    2) у Вас в результирующем запросе применяется условие:
    ГДЕ ВремТаблицаНоменклатураИОстаток.КоличествоОстаток – ВремТаблицаНоменклатураИОстаток.Количество < Лимиты.Лимит
    не помню в каком именно видео, но Вы указывали, что такое условие, т.е. когда в одной из части условия находится вычисляемое выражение, может привести к сканированию или я не верно понял рекомендацию? Я именно по этому решил сначала во вложенном запросе рассчитать это поле "КоличествоОстаток – Количество", а уже "на верху" сравнить с лимитом, в данном случае это излишне?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

      • Дмитрий Абраменко

        Так же еще интересно, чем конструкция “Left Outer Join” и “Left Semi join” различаются и в каких случаях применяется та и другая в соединениях?

        • Андрей Бурмистров


          (текст комментария доступен только участникам Мастер-группы)

          • Дмитрий Абраменко

            А какая конструкция в запросе 1С позволяет оптимизатору использовать Left Semi join? Просто увидел данную конструкцию в Nested Loops в одном из планов запросов в заданиях, а запроса 1С там не было приложено.
            Так же, если не сложно, интересно слово OPTIMIZED в Nested Loops.

            • Андрей Бурмистров


              (текст комментария доступен только участникам Мастер-группы)

              • Дмитрий Абраменко

                Спасибо большое
                А не подскажите конкретные ресурсы или книгу, где можно справляться об операторах с возможным синтаксисом? Может есть какие-то, которые вы порекомендовали бы, чтобы не сканировать постоянно гугл.

                • Андрей Бурмистров


                  (текст комментария доступен только участникам Мастер-группы)

  19. Дмитрий Абраменко

    Добрый день, Андрей.
    Появилось несколько вопросов:

    1) если у нас соединяются левым соединением две виртуальные таблицы Т1 и Т2, имеющие схожие структуры, например: Товар, склад, Характеристика, Количество и мы знаем массив номенклатуры и склад выборки, вопрос: Наложив условия на левую виртуальную таблицу (в ее параметрах), необходимо ли на накладывать условия и на правую таблицу, если соединение будет идти по тем же полям или достаточно соединения по полям Товар и Склад? Оптимизатор самостоятельно не наложит ли эти условия на правую таблицу?

    2) индекс ТЧ документа состоит из ссылки на документ и некоего KeyField, судя по всему это не номер строки, т.к. у него другое имя, что представляет из себя это поле, просто еще один уникальный код?

    3) не могу понять до конца условие, которое накладывает оптимизатор на таблицу итогов:
    WHERE:(([Abramenko_Plazma_Test].[dbo].[_AccumRgT22].[_Fld21] as [T4].[_Fld21]CONVERT_IMPLICIT(numeric(16,0),[@P3],0))
    AND
    ([Abramenko_Plazma_Test].[dbo].[_AccumRgT22].[_Fld21] as [T4].[_Fld21]CONVERT_IMPLICIT(numeric(16,0),[@P4],0))
    понятно, что тут он выбирает не нулевые остатки в таблице, но зачем он добавляет вторую конструкцию (после AND), ведь она идентична первой, на мой взгляд или я ошибаюсь?

    • Дмитрий Абраменко

      почему-то по вопросу 3 режется условие при добавлении комментария…размещу текст в текстовом файле

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

      • Дмитрий Абраменко

        Пример: таблицы имеют одинаковую структуру “Склад,Товар,Количество” запрос получает данные по массиву номенклатуры и по одному складу. Если не использовать ВТ, а написать все в одном соединении:
        ВЫБРАТЬ
        ОстаткиТоваровОстатки.Товар,
        ОстаткиТоваровОстатки.ОстатокНаСкладе,
        ОстаткиРезервовОстатки.КоличествоОстаток КАК ОстатокВРезерве
        ИЗ РегистрНакопления.ОстаткиТоваров.Остатки(,Склад = &СкладИ Товар В (&СписокТоваров)) КАК ОстаткиТоваровОстатки
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиРезервов.Остатки КАК ОстаткиРезервовОстатки
        ПО ОстаткиТоваровОстатки.Склад = ОстаткиРезервовОстатки.Склад
        И ОстаткиТоваровОстатки.Товар = ОстаткиРезервовОстатки.Товар

        Обязательно ли накладывать условие “Склад = &СкладИ Товар В (&СписокТоваров)” в параметры второй виртуальной таблицы ОстаткиРезервовОстатки, если соединение у нас ЛЕВОЕ и идет по тем же полям или можно написать, как в примере, т.е. оставить ее без параметров?

        • Андрей Бурмистров


          (текст комментария доступен только участникам Мастер-группы)

  20. YPermitin

    Андрей, в одном из уроков вы сказали, что в платформа 8.3 изменился подход к работе с временными таблицами. А можете рассказать подробнее?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  21. AlexanderKulikov

    Убежден что в 8-5 идет соединение с виртуальной таблицей оборотов РН а не просто с подзапросом. Причем, соединение производится по полю регистратора. По крайней мере у себя воспроизвел нечто подобное.

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  22. Gostmair

    Ошибся уроком, не там написал. В видео уроке “79 Анализ неоптимальных запросов” при включении анализа запросов в ЦУП вы несколько раз говорить, что будет серьезная нагрузка на систему при включении анализа, поэтому его нужно выполнять короткое время и прочее. А вот при включенном анализе запросов сервисом Гилева таких слов не звучит. В чем принципиальное различие механизмов если один очень грузит систему, а другой нет? Оба же ТЖ анализируют.

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  23. Gostmair

    В уроке “67. Другие причины медленной работы запрос. Нулевые строки.” При выборе остатков из регистра накопления используется оператор Stream aggregate его назначение ясно и почему он выбрался тоже. Но вот при повторении у себя на компьютере примера из урока у меня вместо Stream aggregate был использован опетор Hash Match. Почему? И как в данном случае работает этот оператор, т.к. я думал, что нужен для соединения таблиц, а не для группировки строк?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

  24. Gostmair

    Здравствуйте. Я только сейчас обратил внимание на один момент.
    Если сделать запрос:
    “ВЫБРАТЬ ПЕРВЫЕ 10
    ПродажаТабличнаяЧасть.Ссылка,
    ПродажаТабличнаяЧасть.Товар
    Из
    Документ.Продажа.ТабличнаяЧасть Как ПродажаТабличнаяЧасть”

    То выводятся представления документа продажа и справочника товары, но при этом SQL profiler показывет запрос из одной таблицы табличной части документа. Далее если смотрим содержимое этой таблицы то там только ссылки на документ и товар, т.е. ни какого представления, которое можно было бы вывести в консоль. Как так? От куда появляется представление?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

      • Gostmair

        Я несколько раз внимательно просмотрел трассировку, но запросов на получение представления после основного так и не увидел. А может быть, что так какие-то другие события должны быть настроены в SQL Profiler?

        • Андрей Бурмистров


          (текст комментария доступен только участникам Мастер-группы)

          • Gostmair

            Я нашел эти запросы, но заметил другую закономерность. Когда выполняешь запрос в консоли первый раз они появляются, если выполнить повторно то их уже нет в трассировке. Где сохраняются значения представлений в промежутке выполнения, если не видно чтения из кэша?

            • Андрей Бурмистров


              (текст комментария доступен только участникам Мастер-группы)

  25. Shcheglov

    Возник вопрос по ходу решения: а как на сервере СУБД будет выглядеть работа с табличной частью объекта как таблицей значений? Например, ТабличнаяЧасть.Выгрузить().Свернуть(“Товар”, “Количество”) прямо в модуле документа-объекта?

    • Андрей Бурмистров


      (текст комментария доступен только участникам Мастер-группы)

Комментарии закрыты