При разработке отчетов и сложных алгоритмов в 1С программисты часто сталкиваются с задачей получения остатков не на одну конкретную дату (которую легко передать в параметры виртуальной таблицы), а на целый список произвольных дат. Стандартная виртуальная таблица Остатки позволяет получить данные только на один момент времени, передаваемый в параметре Период. Если дат много, и они распределены хаотично, использование виртуальной таблицы в цикле или многократные обращения к ней становятся крайне неэффективными.
В данной статье мы разберем, как решить эту задачу в рамках одного запроса, используя физические таблицы движений и механизмы временных таблиц, а также рассмотрим методы оптимизации производительности для больших объемов данных.
Это классический способ, который обсуждался в сообщениях форума. Суть метода заключается в том, чтобы отказаться от использования виртуальной таблицы Остатки и самостоятельно рассчитать итоги, обратившись к записям регистра напрямую. Рассмотрим алгоритм по шагам.
Предположим, у нас уже есть временная таблица ВТ_Даты с колонками Дата, Клиент, Фирма. Нам нужно получить остатки по этим измерениям на каждую указанную дату. Проанализируем структуру запроса:
1. Мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ временной таблицы с физической таблицей регистра накопления.
2. Условие связи устанавливается по измерениям (Клиент, Фирма) и по периоду: Регистр.Период <= ВТ_Даты.Дата.
Разберем пример реализации расчета суммы остатка. Так как в физической таблице нет готового поля «Остаток», мы должны использовать конструкцию ВЫБОР, чтобы правильно учесть приходы и расходы:
ВЫБРАТЬ
Т.Дата КАК Дата,
Т.Клиент КАК Клиент,
Т.Фирма КАК Фирма,
СУММА(ВЫБОР
КОГДА Рег.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА Рег.Сумма
ИНАЧЕ -Рег.Сумма
КОНЕЦ) КАК ОстатокНаДату
ИЗ
ВТ_Даты КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Взаиморасчеты КАК Рег
ПО Т.Клиент = Рег.Клиент
И Т.Фирма = Рег.Фирма
И Рег.Период <= Т.Дата
СГРУППИРОВАТЬ ПО
Т.Дата,
Т.Клиент,
Т.Фирма
Важный нюанс: при использовании условия <= в запросе по физической таблице мы фактически получаем остаток «на конец секунды». Если в эту же секунду были движения, они попадут в расчет. Если вам нужен остаток «на начало», используйте строгое сравнение <.
Метод прямого суммирования физической таблицы (Метод 1) прост в реализации, но имеет существенный недостаток: для каждой даты из вашего списка система вынуждена заново пересчитывать все движения «с начала времен». Если в регистре миллионы записей, запрос будет работать крайне медленно.
Выясним, как оптимизировать этот процесс. Проанализируем более продвинутый подход:
Остатки. Сохраним их во временную таблицу ВТ_НачальныйОстаток.НачальныйОстаток + ОборотыДоТекущейДаты.Такой подход значительно снижает нагрузку на базу данных, так как мы не сканируем исторические данные многократно для каждой строки списка.
Часто возникает ситуация, когда на определенную дату из вашей таблицы в регистре вообще не было движений. В этом случае простое внутреннее соединение может исключить такую дату из результата. Чтобы этого не произошло, всегда используйте ЛЕВОЕ СОЕДИНЕНИЕ от таблицы дат (ВТ_Даты) к таблице движений или итогов.
Проанализируем ситуацию: если движений не было, сумма по полю Остаток может вернуться как NULL. Не забудьте обработать это значение функцией ЕСТЬNULL(..., 0), чтобы в отчете красовался ноль, а не пустое поле.
Для обеспечения максимальной скорости работы запроса необходимо соблюдать правила индексации. Рассмотрим основные моменты:
Индексация временных таблиц: Всегда индексируйте временную таблицу ВТ_Даты по тем полям, по которым происходит соединение. В нашем примере это Дата, Клиент и Фирма.
ИНДЕКСИРОВАТЬ ПО
Дата,
Клиент,
Фирма
Понятие Границы (Boundary): В 1С существует объект Граница, который определяет, включать ли момент времени в расчет. В запросах это моделируется условиями сравнения. Если ваша задача — получить остаток на КОНЕЦПЕРИОДА(Дата, ДЕНЬ), убедитесь, что условие в запросе корректно обрабатывает время 23:59:59. Использование <= КОНЕЦПЕРИОДА(Дата, ДЕНЬ) является наиболее безопасным вариантом для получения остатка на конец дня.
Мы рассмотрели несколько способов получения остатков на произвольные даты. Выбор метода зависит от объема данных:
СУММА).Помните, что грамотное использование временных таблиц и индексации — залог стабильной работы вашей системы 1С.