Приемы работы с СКД: делаем за 5 минут то, на что у других уйдет час

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

Я поделюсь опытом, как сложное сделать простым: как сократить (и даже отказаться) от написания кода при выводе отчетов.

«Лучше день потерять, потом за 5 минут долететь…» – это на 100% про систему компоновки данных. Механизмы компоновки многим непонятны – не очевидно, что это, зачем это нужно и как работает. Но в компоновке надо разбираться, потому что она открывает очень интересные возможности.

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

 

Как избежать вывода отчета «кодом»

Начнем с первого вопроса – как избежать того, чтобы выводить отчет «кодом», как сделать его на компоновке, не прибегая к сложным запросам.

 

Вывод для проекта пройденных и предстоящих контрольных точек

Приведу пример из личного опыта. В нашей компании отдел разработки автоматизирован на системе 1С:СППР – это система фактического учета задач. Каждая задача делится на контрольные точки, и разработчик при ее выполнении отмечает, что контрольная точка пройдена.

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

Когда я отдал отчет на разработку, разработчик ответил мне, что на это нужно минимум полдня работы. Я очень удивился, потому что, на мой взгляд, это делается за 10-15, может быть, 20 минут. Начал разбираться.

Оказалось, что разработчик хотел в процедуре «ПриКомпоновкеРезультата» составить таблицу значений с этапами, обработать ее в цикле (для определения того, пройден этап или еще нет), а в одной из колонок будет в виде текста скомпонованы нужные мне этапы. Результат в свою очередь подать на вход компоновки с помощью набора данных вида «Набор-объект».

 

Очень сложно и непонятно. Действительно, работы больше, чем на полдня и хорошо, если уложится.

На самом деле, эта задача очень просто решается с помощью компоновки данных. Для ее решения нужно всего две строчки кода.

  • Готовим данные путем объединения запросов – выбираем все необходимые контрольные точки и технические проекты.

 

И с помощью функций «СоединитьСтроки» и «ТаблицаЗначений» выводим пройденные и предстоящие этапы в качестве отдельных полей-ресурсов.

В результате получается то, что надо – пройденные и предстоящие этапы в отдельных колонках строки.

Что делает функция «ТаблицаЗначений»? Эта функция по детальным записям собирает таблицу значений, которую можно подать на вход функции «СоединитьСтроки». Таким образом, получается нужная строка с переносами.

 

ABC-анализ разработчиков в разрезе ошибок

Другой пример. Я захотел посмотреть, кто больше всех в отделе «косячит» – решил провести ABC-анализ разработчиков в разрезе ошибок.

Что это значит? Берем разработчиков, упорядочиваем по количеству ошибок. Первые 20% этого списка – хорошие разработчики, «косячат» мало., следующие 30% – середнячки, и оставшиеся 50% – самые «косячники».

На компоновке эта задача решается очень просто – за пять или семь минут. Хотя, казалось бы – надо упорядочить таблицу, как-то посчитать эти классы, где-то их зафиксировать… На самом деле, ничего этого не надо.

Первый вариант

Мы прямо в ресурсе вызываем функцию общего модуля, которой на вход подаем результат встроенной в СКД функции «ГрупповаяОбработка».

Что делает функция «ГрупповаяОбработка»? Она возвращает все значения группировок в виде таблицы значений. Таким образом, при вызове функции общего модуля можно получить доступ к соседним строкам, чтобы определить класс ABC на основании количества ошибок.

Это первый путь, он длинный. Есть путь еще короче.

 

Второй вариант

В компоновке уже есть встроенная функция «КлассификацияABC», которая позволяет рассчитать класс на основе переданных параметров.

На слайде показан пример того, как отработала функция «КлассификацияABC». Она возвращает число, которое не так сложно привести к значению. Мы видим, что результаты совпадают.

 

Другие функции СКД

На примере функций «ТаблицаЗначений» и «ГрупповаяОбработка» уже можно решить много задач, которые на запросах решаются довольно сложно.

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

 

Как эффективно применить СКД в коде

Почему-то я редко встречаю применение СКД вне отчетов, хотя этот инструмент очень интересный и мощный и позволяет сэкономить строки кода.

Упрощение применения СКД в коде

На слайде показан пример, который я взял из «Яндекса», написав запрос: «Как вывести результат компоновки в таблицу значений». Где здесь оптимизация? Ведь нужно написать кучу кода. Как с помощью этого можно что-то оптимизировать?

Ответ очень простой – используйте свои библиотеки.

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

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

 

Особенности использования СКД в коде

Если вы будете применять систему компоновки данных в коде, то обязательно столкнетесь с одной ее маленькой особенностью.

Например, у нас есть большая выборка номенклатуры, которую нужно обработать в цикле с помощью компоновки данных – мы для каждой номенклатуры получаем некие данные и что-то с ними делаем (куда-то их записываем или используем в каких-то своих алгоритмах).

На слайде приведен пример, где для каждой номенклатуры в цикле создается компоновщик настроек, для него устанавливается параметр «Номенклатура», и выгружается результат.

Если посмотреть замер производительности, мы увидим, что 90% времени уходит на формирование макета компоновки. Что это такое?

 

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

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

Таким образом, мы увидим привычную нам картину, когда основное время уходит на чтение данных и на работу с базой.

 

Советы по разработке собственных фреймворков

Если будете делать для себя какую-то библиотеку для работы с компоновкой, старайтесь делать так, чтобы:

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

 

Примеры упрощения популярных задач

Еще несколько примеров популярных задач, с которыми, так или иначе, сталкивается большинство разработчиков.

 

Накопительный итог

Первая задача – это накопительный итог. Я думаю, каждый сталкивался с ситуацией, когда нужно посчитать значение параметра накопительным итогом. Например, когда в первом периоде у нас было затрачено 10 человеко-часов и во втором периоде – 10 человеко-часов. И при выводе значения трудозатрат для второго периода нам нужно показывать, сколько всего было потрачено времени.

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

ГДЕ ТехПроект = ТехПроект И Период >= Период

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

В компоновке эта задача решается элементарно – с помощью функции «ВычислитьВыражение»:

ВычислитьВыражение("Сумма(Трудозатраты)", , , "Первая", "Текущая", , , )

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

 

Предлагаю сравнить время выполнения запроса и компоновки. Параметры тестового стенда приведены на слайде – это два слабеньких сервера, на одном из них 1С-сервер, на втором SQL-сервер.

Всего было восемь тестов – каждый в рамках своего периода. Для каждого теста параметры, с которыми выполнялся запрос и СКД, подбирались так, чтобы выборка данных примерно соответствовала месячному объему:

  • первый тест – это месячный объем;
  • второй тест – это двухмесячный объем и т.д.

Каждый тест проводился по 10 тыс. раз. Результирующее время было усреднено.

На графике видно, что разницы между СКД и запросами практически нет. А если нет разницы, зачем писать сложные запросы, когда можно решить задачу с помощью компоновки всего в одну строчку.

 

Курсы валют на конец месяца

Следующая задача – это получение курсов валют на конец периода, т.е. поиск ближайшего значения.

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

На компоновке эта задача решается очень просто. Мы делаем два набора.

  • В первом производим получение периодов;
  • Во втором – делаем запрос среза последних;
  • Для этих двух наборов делаем соединение с параметром «Период», используя его в качестве параметра виртуальной таблицы для второго запроса.

В результате, на каждую строчку таблицы периодов будет выполнен запрос со срезом последних. Фактически, это получается запрос в цикле, причем, без кода. Мы не пишем цикл, не заполняем таблицу. Просто делаем два «Набора-запроса» и соединение между ними с передачей параметров – ничего сложного.

Если посмотреть сравнение замеров производительности выполнения запроса в цикле со срезом последних и связи наборов данных в компоновке, то можно увидеть, что разница практически незаметная. Но запрос в цикле писать сложнее и дольше, а использовать компоновку очень просто – два запроса, соединение между ними с передачей параметра, и все.

Другая интересная особенность компоновки состоит в том, что при соединении наборов данных есть возможность использования списка параметров. Это – очень интересный флажок. Если вы его ставите, то значения выражений источников передаются в подчиненный набор в виде списка значений по 1000 записей.

Это – очень интересная возможность. Если у вас в компоновке используется несколько соединений, с помощью списка значений можно ограничить выборку из подчиненного набора.

Применение СКД позволяет сэкономить множество строчек кода:

  • «ВычислитьВыражение» упрощает расчет накопительного итога;
  • Очень удобно использовать подзапросы;
  • Используя свои библиотеки, мы намного удобнее работаем с компоновкой, чем, если бы работали напрямую с этими объектами.

 

Как искать ошибки в СКД?

Итак, мы научились использовать функции в компоновке, но что-то пошло не так. Как искать в компоновке ошибки?

Часто бывает, что сообщение с информацией, которое выдает компоновка, не информативно, и непонятно, что система от разработчика хочет.

 

Рассмотрим простой пример. Допустим, есть запрос, который из справочника технических проектов выбирает проекты и их заказчиков. Запрос простой, всего три строчки.

 

 

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

Давайте посмотрим, что получается в макете компоновки.

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

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

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

 

Заключение

Мы поговорили о том, как:

  • Вывести отчет СКД несмотря на сложные потребности
  • Вместо кода использовать функции СКД
  • Применять СКД не только для отчетов
  • Решать некоторые из популярных задач с помощью СКД
  • Искать ошибки в СКД

Я показал несколько примеров, как можно оптимизировать свою работу со схемой компоновки данных, и, надеюсь, пробудил у вас интерес к этой теме.

Изучайте СКД – это поможет вам сделать свой код совершеннее!

 

****************

Данная статья написана по итогам доклада, прочитанного на конференции INFOSTART EVENT 2024 COMMUNITY. Больше статей можно прочитать здесь.

В 2024 году приглашаем всех принять участие в 7 региональных митапах, а также юбилейной INFOSTART EVENT 2024 в Москве.

Выбрать мероприятие.

26 Comments

  1. Dzenn

    Что один будет делать 20 минут, другой будет делать три дня, и это нормально.

    Reply
  2. karpik666

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

    Reply
  3. bulpi

    Плохо, что нет толковых книг с примерами по этим вопросам. Или я их не знаю.

    Reply
  4. qwinter

    Шо? Опять?

    Reply
  5. dreamcreal

    Классно.

    Reply
  6. HAMMER_59

    «Вот, всего две строчки кода!»

    На днях писал обработку заполнения для документа «Бухгалтерская операция», для различных конфигураций, в т.ч. для КА 1, и БП 2, в которых обработки заполнения не поддерживаются. Пришлось искать альтернативные варианты, сделал через внешнюю печатную форму.

    С заполнением трудностей не возникло, а вот как обновить данные после заполнения на форме. Всего три строчки кода :), но именно на эти три строчки кода ушло больше всего времени.

    Reply
  7. SergeyN

    (6)

    С заполнением трудностей не возникло, а вот как обновить данные после заполнения на форме. Всего три строчки кода :), но именно на эти три строчки кода ушло больше всего времени.

    Напоминает старый анекдот про «1$ за удар, 999$ за то, что знаю куда ударить». Для этого мы здесь и делимся знаниями, что бы экономить время на «на три строчки кода» ))

    Reply
  8. Pwnish3r

    В результате, на каждую строчку таблицы периодов будет выполнен запрос со срезом последних. Фактически, это получается запрос в цикле, причем, без кода. Мы не пишем цикл, не заполняем таблицу. Просто делаем два «Набора-запроса» и соединение между ними с передачей параметров – ничего сложного.

    Эту же задачу можно решить в 1 корреляционный запрос.

    Reply
  9. SergeyN

    (8)

    ожно решить в 1 корреляционный

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

    Reply
  10. Бубузяка

    Очень позитивная статья. Спасибо.

    Reply
  11. Terve!R

    Спасибо, интересно!

    Только фреймворков для скачивания не хватает.

    Все свелось к «посмотрите как круто я могу». А кто сможет это повторить, кроме Вас?)

    Reply
  12. s_vidyakin

    (9) Разве корреляционные запросы поддерживаются 1С ??

    Reply
  13. SergeyN

    (12) Да. Такой вариант вполне рабочий:

    ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка КАК Ссылка,
    РеализацияТоваровУслуг.СуммаДокумента / КурсыВалют.Курс КАК СуммаДокумента
    ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
    ПО (КурсыВалют.Валюта = &ВалютаОценки)
    И (КурсыВалют.Период В
    (ВЫБРАТЬ ПЕРВЫЕ 1
    Фильтр.Период
    ИЗ
    РегистрСведений.КурсыВалют КАК Фильтр
    ГДЕ
    Фильтр.Период <= РеализацияТоваровУслуг.Дата
        УПОРЯДОЧИТЬ ПО
    Фильтр.Период УБЫВ))

    Показать

    В условии отбор по таблице из вышстоящего запроса.

    Reply
  14. SergeyN

    (11) см модули

    ФинансоваяОтчетностьСервер

    КомпоновкаДанныхСервер

    в типовых УТ11, КА2, ЕРП2

    Начать можно с адаптации под ваши задачи функций из этих модулей.

    Reply
  15. kalyaka

    (12) поддерживаются только для операции В, вот цитата из справки:

    Заметим, что из запроса операции В возможно обращение к полям таблиц, которые встречались во внешнем запросе до появления операции
    Reply
  16. nytlenc

    Многабукаф, не осилил.

    Reply
  17. echo77

    (16) Добавьте в мемориз, читайте по частям. Я тоже не осилил с первого раза 🙂

    Reply
  18. echo77

    (0) Замеры Подзапросов в СКД и запросов в цикле показали почти одинаковые результаты — не мудрено, и тут и там по сути запрос в цикле.

    Вот эта (https://infostart.ru/public/77568/) статья хорошая — объясняется как получить срез на каждую дату в запросе. Кстати, ее писал владелец ресурса http://1cskd.ru/. В итоге, я делаю срезы на каждую дату в запросе и научил всех своих коллег делать так же.

    Знать возможности СКД — это очень хорошо, но не обязательно их все применять.

    Посмотрите мои статьи по СКД тоже.

    Reply
  19. Lapitskiy

    Отличная статья с примерами. Годится как пособие по СКД.

    Есть одно «но» — автор грешит упрощениями типа «5 минут». Видимо работы с крупными компаниями или проектами/конфигурациями нет или мало.

    Сейчас чтобы понять, «а что там в УТ 11» 🙂 это надо полдня сидеть над кодом, а потом на всякий случай отдать на тестирование.

    Еще момент — а процесс обсуждения и ознакомления разработчика с ТЗ — почему его не включаете? Есть такие «спецы» по объяснению ТЗ — чтобы их понять, потребуется также полдня.

    Reply
  20. Lapitskiy

    (7) это да, согласен

    Reply
  21. fly_men

    Спасибо за опыт, одной граблей меньше.

    Reply
  22. unichkin

    Обычная история.. Все это зависит от опыта программиста, и особенно — от его желания «сделать лучше». Далеко не каждый относится к задачам как к экзамену своих способностей, где нужно подумать решить наиболее оптимально.. Совсем недавно переделывал за одним товарищем — то, что он писал три дня (и не работало) — я налабал за ~5 часов, и взлетело. Все дело в опыте, и желании качественно решать задачи.

    В такой статье неплохо бы упомянуть о консоли СКД из инструментов разработчика — где можно быстро и удобно разработать запрос и схемы отчета. Главное — возможность «на лету» видеть запрос, который генерирует СКД. У меня уже сложился некий тех. процесс — если нужен отчет на СКД, схему я разрабатываю именно там, уже потом добавляю ее в отчет, и при необходимости рисую формы и прочее.

    Reply
  23. ids79

    Первую задачу можно еще решить использую функцию «ВычислитьВыражениеСГруппировкойТаблицаЗначений». Результат аналогичный получится.

    Reply
  24. strek_ivan

    И ведь всё актуально и по сей день!

    Reply
  25. vpaoli

    картинки мелкие и не читаются, жаль

    Reply
  26. seka09

    То что выполнялось у меня на скд 15 мин, запросом пару часов выполнялось. Я не согласен что разницы нет выполнения запроса или скд. Разница очень большая. Для больших объемов данных скд как раз и необходимо.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *