Как правильно получить последний документ внутри одной секунды в запросе 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработчика 1С часто возникает ситуация, когда в информационной базе создается множество документов с абсолютно одинаковой датой (с точностью до секунды). Это типично для пакетной обработки данных, загрузок из внешних систем или работы в высоконагруженных базах. В таких случаях стандартной сортировки по дате становится недостаточно. Мы начинаем задаваться вопросом: вернет ли функция МАКСИМУМ(Ссылка) в запросе действительно последний сформированный документ?

Разберем эту задачу подробно, проанализируем механизмы работы платформы и выясним, как СУБД обрабатывает ссылки на самом деле.

Механизм сравнения ссылок в 1С

Для начала проанализируем, что представляет собой Ссылка (или GUID) с точки зрения базы данных. В 1С ссылка — это 128-битное число (UUID версии 1), которое хранится в SQL-таблицах в поле типа binary(16). Когда мы используем агрегатную функцию МАКСИМУМ к полю ссылки, платформа транслирует это в SQL-команду MAX().

Важно понимать следующие моменты:

  1. Бинарный порядок: Сравнение ссылок происходит побайтово. Платформа 1С проектирует свои GUID таким образом, чтобы они были «почти» последовательными (используется модифицированный алгоритм, где временная метка выносится в старшие байты при записи в БД). Это обеспечивает физическую запись новых данных в конец таблиц для оптимизации индексов.
  2. Детерминированность: Порядок ссылок внутри одной секунды в 1С является строго детерминированным. Это значит, что если документ А «больше» документа Б, то это положение сохранится навсегда. Именно на этом свойстве строится механизм Момента времени.
  3. Составные типы: Если мы работаем с полем Регистратор в регистрах, мы имеем дело с составным типом данных. В этом случае МАКСИМУМ сначала сравнивает идентификатор типа документа (внутренний номер метаданных), а уже затем — бинарные данные самой ссылки.

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

Рассмотрим ситуацию, когда нам нужно получить последний приход по списку товаров, где документов в одной секунде может быть много. Просто применить МАКСИМУМ(Регистратор) в одном запросе с группировкой по номенклатуре может быть недостаточно, если в этой же секунде есть документы разных типов.

Разберем по шагам наиболее надежный метод с использованием временных таблиц:

Шаг 1. Получение максимальной даты (периода) для каждого объекта.

Сначала мы находим саму временную точку, в которой было совершено последнее движение.


ВЫБРАТЬ
    Продажи.Номенклатура КАК Номенклатура,
    МАКСИМУМ(Продажи.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_МаксПериод
ИЗ
    РегистрНакопления.Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
    Продажи.Номенклатура
;

Шаг 2. Получение максимальной ссылки внутри найденной секунды.

Теперь проанализируем ситуацию: в найденную секунду МаксПериод могло попасть несколько документов. Чтобы выбрать из них «самый последний», мы соединяем исходную таблицу с нашей временной таблицей и берем максимум по ссылке.


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

Такой двухэтапный подход гарантирует, что мы получим документ с максимальным бинарным значением ссылки внутри максимальной секунды. В 99% случаев это будет именно тот документ, который был введен последним.

Альтернативный метод: Использование Момента времени

Рассмотрим более простой вариант, если нам нужно получить только один, самый последний документ в целом (без группировки по списку товаров). В 1С объект МоментВремени — это комбинация Дата + Ссылка. Хотя мы не можем использовать МАКСИМУМ(МоментВремени) в языке запросов, мы можем использовать упорядочивание.

Посмотрим на пример:


ВЫБРАТЬ ПЕРВЫЕ 1
    Док.Ссылка КАК ПоследнийДокумент
ИЗ
    Документ.ПриходнаяНакладная КАК Док
УПОРЯДОЧИТЬ ПО
    Док.МоментВремени УБЫВ

Этот способ является методологически самым верным, так как он напрямую использует механизм платформы для разрешения коллизий внутри одной секунды. При выполнении этого запроса СУБД фактически выполнит сортировку сначала по полю Дата, а затем по бинарному представлению GUID.

Почему МАКСИМУМ(Ссылка) может не сработать?

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

  1. Распределенные базы данных (РИБ): Если документы создаются в разных узлах и синхронизируются, порядок их генерации GUID в разных базах может не совпадать с хронологией их попадания в центральную базу.
  2. Ручная установка ссылок: Если в коде используется метод УстановитьСсылкуНового(), разработчик может назначить документу абсолютно любой идентификатор, что нарушит естественный порядок.
  3. Типы документов: Как мы выяснили ранее, при сравнении Регистратора (составной тип) решающую роль играет внутренний идентификатор метаданных. Если документ типа «А» имеет ID типа 10, а документ типа «Б» — ID 20, то при одинаковой дате МАКСИМУМ всегда выберет документ типа «Б», вне зависимости от времени его создания.

Практические рекомендации

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

Таким образом, МАКСИМУМ(Ссылка) является рабочим инструментом в рамках одной секунды, но его использование требует понимания того, как устроены типы данных в 1С и как работает бинарное сравнение в СУБД.

← На главную