Нарастающие итоги в запросе и методы ускорения его выполнения.

19.10.09

Разработка - Запросы

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


Любезные критики, смотрите P.S. к статье.
Есть множество задач, в которых требуется получение и/или обработка нарастающих итогов. В частности это дебиторская/кредиторская задолженность и расчетные листки. Задача легко решается в рамках встроенного языка, но по разным причинам это не всегда приемлемо (подробнее см. P.S.).  Язык запросов 1с позволяет получить нарастающие итоги. Как подсказывает логика, итоги должны нарастать относительно какого-либо показателя. Самый распространенный случай – период. Именно такой случай и будет рассматривать. Так как лично столкнулся с необходимостью использования нарастающих итогов в рамках анализа дебиторской задолженности, то и в статье будем рассматривать её.
Итак, для чего при анализе дебиторской задолженности могут потребоваться нарастающие итоги? Для формирования списка документов по текущей задолженности (при этом абсолютно не важно с какой степенью детализации ведутся взаиморасчеты – алгоритм такой же). Этот список даёт важную информацию для дальнейшего анализа – дата возникновения задолженности, число дней долга, если есть параметр числа дней задолженности, то количество дней просрочки, сумма просроченного долга, ну и сам список документов долга.
Для начала нам потребуется получить список документов взаиморасчетов контрагента:
Реализация товаров и услуг №1          500р
Реализация товаров и услуг №2          1000р
Платежное поручение исходящее №1 -500р
Реализация товаров и услуг №3          1200р
Итого                                                  2200р

Для того чтобы получить нарастающий итог нужно использовать ещё одну такую же таблицу и связать её с первой. Связывать нужно по дате (при совпадении времени можно дополнительно сравнивать по моменту времени), но связывать не через равенство, а через сравнение >= или
Реализация товаров и услуг №1           500р 500р
Реализация товаров и услуг №1           500р 1000р
Реализация товаров и услуг №1           500р -500р
Реализация товаров и услуг №1           500р 1200р
Реализация товаров и услуг №2           1000р 1000р
Реализация товаров и услуг №2           1000р -500р
Реализация товаров и услуг №2           1000р 1200р
Платежное поручение исходящее №1 -500р -500р
Платежное поручение исходящее №1 -500р 1200р
Реализация товаров и услуг №3           1200р 1200р


Как-то некрасиво…А, ну да! Нужно сгруппировать по всем поля Основного списка с суммированием поля вспомогательного. В итоге получим искомое:

Реализация товаров и услуг №1           500р 2200р
Реализация товаров и услуг №2           1000р 1700р
Платежное поручение исходящее №1  -500р 700р
Реализация товаров и услуг №3           1200р 1200р


Пример запроса

ВЫБРАТЬ
    ПериодыИзменения.Период КАК Время,
    СУММА(Регистр.СуммаОборот) КАК Сумма
ИЗ
    (ВЫБРАТЬ РАЗЛИЧНЫЕ
        ПродажиПоДисконтнымКартам.Период КАК Период
    ИЗ
        РегистрНакопления.ПродажиПоДисконтнымКартам КАК ПродажиПоДисконтнымКартам
    ГДЕ
        ПродажиПоДисконтнымКартам.ДисконтнаяКарта = &Ссылка) КАК ПериодыИзменения
        ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
            ПродажиПоДисконтнымКартамОбороты.Период КАК Период,
            ПродажиПоДисконтнымКартамОбороты.СуммаОборот КАК СуммаОборот
        ИЗ
            РегистрНакопления.ПродажиПоДисконтнымКартам.Обороты(, , Регистратор, ДисконтнаяКарта = &Ссылка) КАК ПродажиПоДисконтнымКартамОбороты
        ГДЕ
            ПродажиПоДисконтнымКартамОбороты.ДисконтнаяКарта = &Ссылка) КАК Регистр
        ПО ПериодыИзменения.Период >= Регистр.Период

СГРУППИРОВАТЬ ПО
    ПериодыИзменения.Период


Все…..можно было бы и так сказать, но у такого решения есть один существенный недостаток – с ростом числа строк в таблице время выполнения запроса увеличивается геометрически (или экспоненциально). Для ускорения требуется оптимизация. Приведу 3 способа:
1. Ограничить период в запросе. Самый распространенный (честно говоря единственный найденный мной на степях интернета), позволяет ограничить число строк в таблице, а значит и ускорить время запроса. Наиболее легкий способ, но имеет недостаток – всё что не входит в период не суммируется – можно и не угадать с периодом, да и необходимее периоды иногда бывают очень большими.

2. Метод последовательного приближения. Строго говоря, метод не ускоряет получения нарастающих итогов для всей таблицы, а только ускоряет поиск нужного значения с использованием нарастающих итогов. Вернемся к примеру с дебиторской задолженностью. Таблица документов долга не будет совпадать со всей таблицей – 500 рублей уже заплатили. Нам требуется получить таблицу с документами возникновения долга (реализация) сумма которых в обратном порядке от последнего числа равна текущему долгу 2200р. Для таких малых таблиц ускорение не требуется, но когда речь идет о большом количестве контрагентов и взаиморасчетах за несколько лет, то можно применить метод последовательного приближения. Идея заключается в том, чтобы сгруппировать документы по периоду и детализировать только нужные периоды. Удобнее всего это делать через пакетные запросы. В моем случае я использовал следующий алгоритм: сначала получил 3 дополнительные таблицы: группировка по годам, группировка по месяцам и группировка по дням. Сначала уже известным способом для таблицы по годам рассчитываем нарастающие итоги. Далее получаем из неё 2 таблицы: если сумма долга с нарастанием для года меньше общего долга, то включаем его в таблицу безусловного включения в конечную таблицу, а первый год, где итоговая сумма больше долга (год с минимальным превышением), отправляем в таблицу для дальнейшего рассмотрения и не забываем передать туда сумму остатка долга (общая сумма долга минус сумма долга из таблицы безусловного включения). Именно по этой таблице отбираем данные из таблицы сгруппированной по месяцам. И также как для таблицы с годами, делим её на 2 таблицы по сумме остаточного долга. Далее таблицу для дальнейшего рассмотрения используем для отбора в таблице по дням. Ну и после делаем всё тоже самое для дальнейшего рассмотрения по дням и основной таблицы.. В результате мы получаем следующие таблицы: безусловное включение по годам, безусловное включение по месяцам, безусловное включение по дням и документы долга в первый день (наиболее удаленные от дня отчета) долга. В последней фазе отбираем из основной таблицы конкретные документы с использованием вышеперечисленных таблиц. Объединяем и вуаля! Готовая таблица документов долга.
Недостаток этого метода – сложность реализации. Сама реализация на //infostart.ru/public/20221/ - ссылка на файл "Новый запрос"

3. Метод сложения периодов. Более универсальный метод и позволяет ускорить именно получение нарастающих итогов. При расчете нарастающих итогов в условие связи добавляется дополнительное условие, чтобы разделить общую таблицу на подтаблицы (желательно помельче). Далее последовательно объединяем эти подтаблицы в более крупные подтаблицы с нарастанием итогов - к каждому последующему периоду прибавляется итоги (последняя сумма в подтаблице) предыдущих периодов. И так далее в зависимости от выбранного для конкретного случая числа итераций.
Недостаток метода – тоже достаточная сложность реализации и то, что этот метод не разработан в деталях – я окончательно его сформулировал только что.

P.S. «Не надо ругать пианиста, он играет как умеет». Я работаю с 8кой, поэтому не могу сказать, что частности реализации методов для 7ки будет таким же (если это вообще возможно), но общие алгоритмы универсальны.

По поводу необходимости получать нарастающие итоги в запросе - в 1с 8 есть возможность создание отчетов с помощью мастеров только из запроса, не используя встроенный язык. Это существенно ускоряет создание отчетов. И когда отчет сам по себе очень прост, то переходить из-за нарасающих итогов на встроенный язык нецелесообразно. Второй случай, когда структура выводимых данных иерархична и строится в нескольких разрезах - язык запросов более гибок. Пример в статье дан именно как пример, для лучшего понимания алгоритма - в реальной задаче такой частный случай с одним клиентом и одним показателем легче решить встроенным языком. Кроме того, как я уже говорил в статье, у запросного метода есть один глобальный недостаток - рост времени выполнения при увеличении объема исходных данных. Но недостаток это можно устранить сложными методами оптимизации, после которых запрос выполняется быстрее встроенного языка.

Метод подсчета нарастающих итогов известен и много раз публиковался на форумах, но именно подробной статьи не было. Метод простой, и статья только про него вышла бы очень короткой. Поэтому добавил описание методов ускорения расчетов. 1 метод используют для ускорения расчетов только запросом (если ускорение вообще используется) все отчеты по задолженности, которые я рассматривал. И в некоторых комментариях я уже писал, что ограничение глубины рассмотрения задолженности – это метод Александра Македонского для узлов – проблема вроде бы решена, только веревка уже не целая. 2 метод я использую для своих отчетов по дебиторской задолженности. После применения этого метода время исполнения отчета для достаточно крупной базы (по всем покупателям) уменьшилось с более 30 минут, до минуты и менее – и не надо про производительность и т.д. всё это уже проверялось. Все варианты отчетов можно посмотреть в моих разработках, в т.ч. и запрос по методу 2 в чистом виде. Ну и 3 метод мне пока не требовался и окончательно я его сформулировал только сейчас. Дискуссия и плюсование поощряется.

См. также

Infostart Toolkit: Инструменты разработчика 1С 8.3 на управляемых формах

Инструментарий разработчика Роли и права Запросы СКД Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    124533    681    389    

732

Пропорциональное распределение в запросе с использованием АвтоНомерЗаписи()

Запросы Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Часто поступают задачи по произвольному распределению общих сумм. После распределения иногда пропадают копейки. Суть решения добавить АвтоНомерЗаписи() в ВТ распределения, и далее используя функции МАКСИМУМ или МИНИМУМ можем положить разницу копеек в первую или последнюю строку знаменателя распределения.

11.04.2024    1966    andrey_sag    6    

25

Для чего используют конструкцию запроса "ГДЕ ЛОЖЬ" в СКД на примере конфигурации 1С:ERP

Запросы СКД Платформа 1С v8.3 Запросы Система компоновки данных 1С:ERP Управление предприятием 2 Бесплатно (free)

В типовых конфигурациях разработчики компании 1С иногда используют в отчетах, построенных на СКД, такую конструкцию, как "ГДЕ ЛОЖЬ". Такая конструкция говорит о том, что данные в запросе не будут получены совсем. Для чего же нужен тогда запрос?

13.02.2024    5965    KawaNoNeko    23    

25

Набор-объект для СКД по тексту или запросу

Запросы СКД Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Абонемент ($m)

Есть список полей в виде текста, или запрос - закидываем в набор СКД.

1 стартмани

31.01.2024    2135    2    Yashazz    0    

30

Запрос 1С copilot

Инструментарий разработчика Запросы Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Абонемент ($m)

Пишем на человеческом языке, что нам надо, и получаем текст запроса на языке 1С. Используются большие языковые модели (LLM GPT) от OpenAI или Яндекс на выбор.

5 стартмани

15.01.2024    6584    31    mkalimulin    27    

51

PrintWizard: поддержка представлений ЗУП в конструкторе

Инструментарий разработчика Запросы Платформа 1С v8.3 Бесплатно (free)

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

14.12.2023    1871    vandalsvq    7    

29

Объектная модель запроса "Схема запроса" 2

Запросы Платформа 1С v8.3 Запросы Конфигурации 1cv8 Бесплатно (free)

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

06.12.2023    5592    user1923546    26    

46

Начните уже использовать хранилище запросов

HighLoad оптимизация Запросы

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

11.10.2023    16546    skovpin_sa    14    

101
Комментарии
Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
96. anig99 2843 23.11.09 00:25 Сейчас в теме
Бес...т.е. без проблем...(:
97. Ish_2 1104 23.11.09 00:56 Сейчас в теме
(96) Ага ! Обзываться уже начал , злобный Саша !
ты того .. не переборщи , а то плохо про тебя в статье напишу :
Так мол и так , Саша - нехороший человек.
98. anig99 2843 23.11.09 07:20 Сейчас в теме
(97) А я и не написал насчет кого или чего оговорился... (: Не надо всё на себя премерять...(:
103. jk3 66 09.12.09 12:08 Сейчас в теме
Было бы неплохо к текстовому описанию схему нарисовать, хотя бы упрощенную
104. Ish_2 1104 05.01.10 01:01 Сейчас в теме
Кстати, Саша. А ты не задумывался над тем , что задача получения просроченного долга есть лишь частный случай другой задачи ?
Задачи получения всех движений расходных докуметов по регистру партий за период
Действительно , в задаче просроченного долга для каждого контрагента :

S - сумма долга
С1,С2...Сk - последовательность сумм всех документов отгрузки.
Требуется найти такую последовательность С1,С2...Сn, чтобы
S = C1+C2+...+Cn
Грубо говоря , набираем накладные на сумму долга.

А если вместо S взять последовательность S1,S2...Sk (суммы документов прихода), то тогда получим задачу получения всех движений по регистру партий при перепроведении расходных документов.

И эта задача решается тоже при помощи нарастающих итогов.
И тоже одним пакетом запросов , набранном в конструкторе.
108. alina0587 2 16.01.14 00:27 Сейчас в теме
(104) А можно где-то поподробнее прочитать про решение такой задачи запросом?
Заранее спасибо!
105. anig99 2843 07.01.10 16:24 Сейчас в теме
Угу... Тоже задумывался как можно прикрутить это к задаче перепроведения документов... Мне пока приходится после каждого проведения делать запрос по партиям заново... Запрос конечно маленький и быстрый...0,06-0,08 сек и производительность меня устраивает, но множество мелких запросов хотелось бы заменить одним, чтобы сразу получить список всех "неправильных" документов
106. Ish_2 1104 02.04.10 10:41 Сейчас в теме
107. Qseft 05.10.11 16:06 Сейчас в теме
Пора бы 1С о ранжирующих функциях в запросах задуматься (по аналогии SQL)
110. ildarovich 7861 04.03.14 16:30 Сейчас в теме
Если автор темы не возразит, размещу здесь ссылку на свой очень быстрый метод решения этой задачи запросом: http://infostart.ru/public/262300/. Данную статью я в свое время прочел, метод в голове отложился. Так что автору большое спасибо - в моей работе имеется и его вклад.
111. anig99 2843 04.03.14 16:53 Сейчас в теме
(110) прошу обратить внимание на МоментВремени(), чтобы избежать проблем с совпадающими датами.
112. ildarovich 7861 05.03.14 13:35 Сейчас в теме
(111) Я предложил, возможно, спорное, но кажущееся мне более правильное решение - не различать документы при совпадении даты. То есть, если в первой неоплаченной секунде у одного контрагента несколько документов, то посчитать отношение долга к общей сумме документов секунды и считать неоплаченной суммой каждого документа эту долю его суммы. Имеем: три документа одного контрагента в одной первой секунде по 100 рублей и долг 150 рублей. Тогда каждый документ будет не оплачен в сумме 50 рублей. А вообще это редчайшая ситуация и ломать по этому поводу копья вряд ли стоит.
Момент времени упорядочивает документы внутри секунды жестким, "случайным" и неуправляемым образом. Какие основания полагаться на этот порядок при решении о порядке погашения документов? Опять же, если бы случайность была бы "мягкой", то в среднем односекундные документы погашались предложенным мною способом.
113. anig99 2843 06.03.14 08:34 Сейчас в теме
(112) сразу 2 возражения. Момент времени упорядочивает документы внутри секунды совершенно определенным образом, и порядок это сохраняется всегда, т.к. зависит от GUID http://infostart.ru/public/84177/. Но это так, уточнение. А основное возражение такое - множество документов в одну секунду - это не редчайший случай. Во-первых, среди 1сников распространена практика приведения в порядок партий в течении одного дня сменой времени документов (поступление на начало дня, реализации на конец). Во-вторых, при проведении документов будущей датой в режиме неоперативного проведения время документа устанавливается на начало дня. В-третьих, вообще при неоперативном проведении задним числом новый документ устанавливает время за последним документом за эту дату. Если последний документ будет на конец дня, то и все последующие будут на конец дня. В-четвертых, в УПП какое-то время существовал небольшой баг - платежки писали в регистр взаиморасчетов время на начало дня, вне зависимости от времени самого документа.
114. ildarovich 7861 06.03.14 15:16 Сейчас в теме
(113) Я не то, чтобы спорю - все эти обстоятельства я тоже имею ввиду, но делаю другие выводы. Тут вопрос более тонкий и я хотел это подчеркнуть.
Момент времени упорядочивает документы внутри секунды совершенно определенным образом, и порядок это сохраняется всегда
А я пишу
Момент времени упорядочивает документы внутри секунды жестким, "случайным" и неуправляемым образом
Тут нет противоречия, "случайным" - поскольку GUID формируется на основе случайности (условно говоря, а вообще вроде бы там MD5 вычисляется с учетом системного времени). Потом он фиксируется и передвинуть документ внутри секунды нельзя (это о жесткости и неуправляемости). Ну а если пользователь не понимает правила упорядочивания - один раз так, потом так, и не может на это повлиять, то полагаться на момент времени не желательно (так мне кажется).
множество документов в одну секунду - это не редчайший случай
совершенно согласен, но для возникновения конкретной рассматриваемой проблемы требуется совпадения секунды не множества, а ПОДМНОЖЕСТВА документов, имеющих одного контрагента и один тип операции - отгрузка. Кроме того, проблема возникает только тогда, когда эта секунда становится первой секундой неоплаченности.

И, далее, предлагаемое решение не "пасует" в этой ситуации, а просто рассматривает односекундные отгрузки как единые документы с точки зрения взаиморасчетов. Это очень просто объяснить менеджерам. Они видят все (а не один произвольно выбранный) частично оплаченные документы и их общую сумму.
115. 1cprogr_nsk 106 20.10.14 09:59 Сейчас в теме
А как сюда прикрутить МоментВремени? Чтобы нв каждую строку с одинаковым по времени регистратором получить свой итог?
116. anig99 2843 20.10.14 10:37 Сейчас в теме
(115) dr.death, добавьте условие, чтобы для одинакового времени ещё сравнивались ссылки Регистратор1 < Регистратор2. Грубо Момент времени = Дата + Ссылка.
117. 1cprogr_nsk 106 20.10.14 11:36 Сейчас в теме
Спасибо, разобрался. У меня была маленько другая ситуация. Регистратор делал движения по табличной части, следовательно нарастающий итог был только по регистратору... добавил дополнительно сравнение по НомеруСтроки
Оставьте свое сообщение