Часто перед нами встает классическая задача: необходимо получить список «самых свежих» документов в разрезе определенного реквизита (например, по договору, контрагенту или складу). Начинающие разработчики нередко пытаются решить эту задачу "в лоб", используя функцию МАКСИМУМ для поля Ссылка. Разберем вместе, почему такой подход в корне неверен, проанализируем внутреннюю механику платформы 1С:Предприятие и выясним, как правильно выстраивать архитектуру таких запросов.
Предположим, мы пишем следующий запрос:
ВЫБРАТЬ
КакойТоДокумент.Реквизит КАК Реквизит,
МАКСИМУМ(КакойТоДокумент.Ссылка) КАК КакойТоДокумент
ИЗ
Документ.КакойТоДокумент КАК КакойТоДокумент
СГРУППИРОВАТЬ ПО
КакойТоДокумент.Реквизит
Ожидается, что этот запрос вернет самый последний созданный документ для каждого реквизита. Однако на практике результат нас неприятно удивит. Посмотрим подробнее, как формируется уникальный идентификатор (УИД/GUID), который лежит в основе ссылки.
Хотя алгоритм генерации UUID действительно содержит временную метку, платформа 1С переставляет байты этого идентификатора местами для оптимизации индексов в СУБД (например, в MS SQL Server). Кроме того, на формирование УИДа влияют MAC-адрес сервера или рабочего компьютера. А теперь добавим к этому распределенные информационные базы (РИБ) и обмены данными: документы могут прилетать из других узлов с сохранением исходной ссылки, или же ссылки могут устанавливаться программно при загрузке из внешних систем. В результате любая хронология ссылок полностью разрушается. Возрастание GUID-ов в порядке ввода не гарантируется.
Если ссылка не гарантирует порядок, то логично использовать дату документа. Но что делать, если несколько документов записаны в одну и ту же секунду? Возникает коллизия: какой из них считать «максимальным»?
В платформе 1С существует системный объект МоментВремени, который решает эту проблему. Он состоит из двух составляющих: Дата (с точностью до секунды) и Ссылка. Если два документа имеют одинаковую дату, система упорядочивает их по ссылке. Важно понимать: это упорядочивание по ссылке внутри одной секунды не гарантирует, что документ физически был создан позже. Это просто технический костыль (тай-брейкер), который обеспечивает детерминированность — чтобы при каждом выполнении запроса база выдавала стабильный и предсказуемый порядок документов, а не перемешивала их случайным образом.
Поскольку в языке запросов нет функции МАКСИМУМ(МоментВремени), разберем по шагам правильный паттерн решения задачи для списка реквизитов.
МАКСИМУМ(Дата). Результат обязательно помещаем во временную таблицу.Реквизит и Дата.МАКСИМУМ(Ссылка). В данном контексте максимум по ссылке абсолютно корректен, так как он работает исключительно внутри одной секунды для разрешения коллизии.Рассмотрим пример такого кода:
ВЫБРАТЬ
КакойТоДокумент.Реквизит КАК Реквизит,
МАКСИМУМ(КакойТоДокумент.Дата) КАК МаксДата
ПОМЕСТИТЬ ВТ_МаксДаты
ИЗ
Документ.КакойТоДокумент КАК КакойТоДокумент
СГРУППИРОВАТЬ ПО
КакойТоДокумент.Реквизит
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_МаксДаты.Реквизит КАК Реквизит,
МАКСИМУМ(КакойТоДокумент.Ссылка) КАК ПоследнийДокумент
ИЗ
ВТ_МаксДаты КАК ВТ_МаксДаты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.КакойТоДокумент КАК КакойТоДокумент
ПО ВТ_МаксДаты.Реквизит = КакойТоДокумент.Реквизит
И ВТ_МаксДаты.МаксДата = КакойТоДокумент.Дата
СГРУППИРОВАТЬ ПО
ВТ_МаксДаты.Реквизит
Если наша задача — найти один-единственный самый свежий документ для конкретного значения (например, для одного выбранного договора), городить многоэтажные временные таблицы неоптимально. Применим конструкцию ПЕРВЫЕ 1.
ВЫБРАТЬ ПЕРВЫЕ 1
КакойТоДокумент.Ссылка КАК Ссылка
ИЗ
Документ.КакойТоДокумент КАК КакойТоДокумент
ГДЕ
КакойТоДокумент.Реквизит = &ИскомыйРеквизит
УПОРЯДОЧИТЬ ПО
КакойТоДокумент.Дата УБЫВ,
КакойТоДокумент.Ссылка УБЫВ
Платформа транслирует этот запрос в эффективную SQL-инструкцию, и при наличии соответствующих индексов в базе данных система найдет нужный документ моментально, избегая полного сканирования таблицы.
В заключение проанализируем ситуацию с точки зрения грамотной архитектуры 1С. Постоянный поиск «самого последнего документа» напрямую по таблицам документов — признак неоптимального проектирования. Документы предназначены для фиксации хозяйственных операций, а не для быстрого получения актуальных срезов данных.
Если бизнес-логика требует часто получать актуальные состояния (последние цены, текущие статусы, ответственных лиц), необходимо использовать Периодические регистры сведений. При проведении наш документ должен просто делать запись в такой регистр. В дальнейшем мы обращаемся к виртуальной таблице СрезПоследних.
Виртуальная таблица СрезПоследних работает несравнимо быстрее сложных многоэтажных соединений и «под капотом» сама корректно обрабатывает все коллизии совпадения дат вплоть до секунды. Используйте встроенные механизмы платформы по их прямому назначению, и ваши базы данных будут работать стабильно и быстро!