Зачастую при проектировании архитектуры бюджетирования или сложного учета возникает потребность хранить версии корректировок. Представим ситуацию: у нас имеется регистр накопления с измерениями Организация, Статья и НомерКорректировки (число), а также некий ресурс. Наша задача — получить в отчет данные только по максимально проведенной корректировке для каждой пары Организации и Статьи. Разберем по шагам, как правильно составить такой запрос, и проанализируем архитектурные нюансы.
Это классический способ, который позволяет получить срез последних значений для таблиц, не имеющих виртуальной таблицы среза (как регистры сведений). Рассмотрим подробнее алгоритм действий: сначала мы группируем данные по нашим основным измерениям и находим максимум по измерению номера корректировки, а затем соединяем полученный результат с исходной таблицей.
ВЫБРАТЬ
Бюджет.Организация КАК Организация,
Бюджет.Статья КАК Статья,
Бюджет.НомерКорректировки КАК НомерКорректировки,
Бюджет.Ресурс КАК Ресурс
ИЗ
РегистрНакопления.Бюджет КАК Бюджет
ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
Бюджет.Организация КАК Организация,
Бюджет.Статья КАК Статья,
МАКСИМУМ(Бюджет.НомерКорректировки) КАК НомерКорректировки
ИЗ
РегистрНакопления.Бюджет КАК Бюджет
СГРУППИРОВАТЬ ПО
Бюджет.Организация,
Бюджет.Статья) КАК ВложенныйЗапрос
ПО Бюджет.Организация = ВложенныйЗапрос.Организация
И Бюджет.Статья = ВложенныйЗапрос.Статья
И Бюджет.НомерКорректировки = ВложенныйЗапрос.НомерКорректировки
Важно понимать, почему мы используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Левое соединение в данной ситуации не подойдет, так как оно оставит все исходные записи, а наша задача — отсечь те строки, где номер корректировки не является максимальным.
Платформа 1С позволяет проверять вхождение сразу нескольких полей в результат вложенного запроса. Посмотрим на пример, как можно переписать предыдущий запрос более компактно:
ВЫБРАТЬ
Бюджет.Организация КАК Организация,
Бюджет.Статья КАК Статья,
Бюджет.НомерКорректировки КАК НомерКорректировки,
Бюджет.Ресурс КАК Ресурс
ИЗ
РегистрНакопления.Бюджет КАК Бюджет
ГДЕ
(Бюджет.Организация, Бюджет.Статья, Бюджет.НомерКорректировки) В
(ВЫБРАТЬ
Бюджет.Организация КАК Организация,
Бюджет.Статья КАК Статья,
МАКСИМУМ(Бюджет.НомерКорректировки) КАК НомерКорректировки
ИЗ
РегистрНакопления.Бюджет КАК Бюджет
СГРУППИРОВАТЬ ПО
Бюджет.Организация,
Бюджет.Статья)
Такой код выглядит эстетичнее, однако стоит помнить об особенностях оптимизатора СУБД. При больших объемах данных конструкция `В` может быть преобразована в `EXISTS`, что на некоторых серверах (например, PostgreSQL) может привести к выбору неоптимального плана выполнения (Nested Loops).
Если таблица регистра содержит миллионы записей, соединение физической таблицы с ее же сгруппированным вложенным запросом может вызвать таймаут. Проанализируем ситуацию с точки зрения производительности и разобьем задачу на пакеты:
ВТ_ЧерновыеДанные.ВТ_ЧерновыеДанные, группируем по измерениям и находим максимум по корректировке. Помещаем результат во вторую таблицу ВТ_Максимумы.ВТ_ЧерновыеДанные и ВТ_Максимумы внутренним соединением.Разбиение на временные таблицы дает планировщику СУБД четкое представление об объемах данных и позволяет использовать индексы более эффективно.
Выясним причину, почему такие запросы вообще приходится писать. Основная проблема заключается в попытке реализовать механизм версионирования на базе регистра накопления.
Ограничения и рекомендации:
СрезПоследних только для регистров сведений. Размещая номера корректировок в измерении регистра накопления, вы лишаете себя этих готовых и оптимизированных механизмов.Как сделать лучше?
Вместо усложнения запросов к исходному регистру, архитектуру стоит пересмотреть. Если нужно получать актуальный бюджет по последней корректировке, добавьте в процедуру проведения документов запись в параллельный зависимый регистр сведений. При построении отчетов читайте данные из него простым линейным запросом без тяжелых соединений и группировок. Это радикально ускорит работу системы.