С какого релиза в запросах 1С появилась функция АВТОНОМЕРЗАПИСИ() и как правильно её использовать?

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

В процессе разработки на платформе «1С:Предприятие» перед программистами регулярно возникает задача нумерации строк непосредственно в запросе. Долгое время для этого приходилось использовать сложные, неоптимальные обходные пути. Ситуация кардинально изменилась с выходом технологической платформы версии 8.3.13, в которой появился штатный механизм автонумерации строк.

В этой статье мы подробно разберем, начиная с какого релиза доступна функция АВТОНОМЕРЗАПИСИ(), как выглядит её синтаксис, с какими критическими «ловушками» СУБД можно столкнуться при её использовании и как эта функция соотносится с другими механизмами платформы, такими как группирующие наборы GROUPING SETS.

В каком релизе появилась функция АВТОНОМЕРЗАПИСИ()?

Возможность создания поля с уникальными, последовательно возрастающими значениями была реализована в платформе «1С:Предприятие» начиная с версии 8.3.13.1513.

Основная цель внедрения этой функции — упростить и ускорить процесс создания монотонно возрастающего уникального ключевого поля для временных таблиц. До появления этого механизма разработчикам приходилось жертвовать производительностью базы данных или писать избыточный код на встроенном языке.

Синтаксис и жесткие ограничения использования

Функция АВТОНОМЕРЗАПИСИ() работает на уровне СУБД и транслируется в создание автоинкрементного поля. Однако платформа накладывает ряд строгих ограничений на её применение:

  1. Только во временных таблицах: Функция может быть использована исключительно при создании временной таблицы (то есть в запросе обязательно должна присутствовать конструкция ПОМЕСТИТЬ ИмяВременнойТаблицы). В обычных выборках, возвращающих результат в код, использовать её нельзя.
  2. Только в списке выборки: Функцию запрещено использовать внутри выражений (например, нельзя написать АВТОНОМЕРЗАПИСИ() + 1) или в условиях связи/отбора.
  3. Запрет в объединениях на верхнем уровне: Не поддерживается использование функции в запросах, содержащих операторы ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ на самом верхнем уровне иерархии запроса.
  4. Один счетчик на таблицу: В рамках одного запроса создания временной таблицы допускается использовать только один элемент списка выборки с функцией АВТОНОМЕРЗАПИСИ(). Создать две независимые колонки со счетчиками в одной таблице физически невозможно.
  5. Тип данных: Функция всегда возвращает системное целое число без дробной части (тип Число).

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


ВЫБРАТЬ
    АВТОНОМЕРЗАПИСИ() КАК НомерСтроки,
    СпрНоменклатура.Ссылка КАК Номенклатура,
    СпрНоменклатура.Наименование КАК Наименование
ПОМЕСТИТЬ ВТ_НумерованныйСписок
ИЗ
    Справочник.Номенклатура КАК СпрНоменклатура
ГДЕ
    СпрНоменклатура.ЭтоГруппа = ЛОЖЬ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.НомерСтроки,
    ВТ.Номенклатура,
    ВТ.Наименование
ИЗ
    ВТ_НумерованныйСписок КАК ВТ

Главная «ловушка» АВТОНОМЕРЗАПИСИ() (Особенности кэширования СУБД)

Многие разработчики совершают опасную ошибку, полагая, что нумерация в таблице всегда гарантированно начинается с единицы. В официальной документации указано: «Начальное значение счетчика зависит от используемой СУБД и, в общем случае, может быть любым». На практике это выливается в серьезную проблему, связанную с кэшированием соединений в СУБД (MS SQL Server, PostgreSQL).

Проанализируем, как ведет себя счетчик при повторных запусках запроса в рамках одного сеанса:

Где это критично?

Во-первых, при использовании функции в динамических списках или при проведении документов, где разработчик делает отбор вида ГДЕ НомерСтроки = 1 (например, для защиты от дублирования записей). При быстром перепроведении документа запись может «исчезнуть» из итоговой выборки, так как её номер внезапно станет равен 6 вместо ожидаемого 1, а спустя 10 минут «магическим» образом вернуться назад.

Во-вторых, при соединении двух временных таблиц по полю автонумерации. Если в одной таблице счетчик начался с 1, а во второй (из-за кэширования в параллельном процессе) — с 20, то в результате соединения вы получите абсолютно пустую таблицу или некорректно сопоставленные данные.

Важная особенность отладки: В файловом режиме работы базы данных (на локальном компьютере разработчика) этот эффект практически не воспроизводится — там нумерация почти всегда стабильно начинается с 1. Это усыпляет бдительность, и критическая ошибка уходит на рабочий клиент-серверный сервер.

Как решали задачу нумерации до версии 8.3.13?

Чтобы понять ценность появления АВТОНОМЕРЗАПИСИ(), вспомним, какие обходные пути приходилось использовать программистам ранее, и проанализируем их недостатки:

  1. Перекрестное (квадратичное) соединение таблицы самой с собой. Таблица соединялась сама с собой по условию Т1.УникальныйКлюч >= Т2.УникальныйКлюч, после чего выполнялась группировка и подсчет количества строк.

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

    
    ВЫБРАТЬ
        Т1.Ссылка КАК Номенклатура,
        КОЛИЧЕСТВО(Т2.Ссылка) КАК НомерСтроки
    ИЗ
        Справочник.Номенклатура КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Т2
            ПО Т1.Ссылка >= Т2.Ссылка
    СГРУППИРОВАТЬ ПО
        Т1.Ссылка
    

    Этот метод имеет вычислительную сложность O(N²). Если в таблице несколько десятков тысяч строк, такой запрос гарантированно приводил к колоссальному падению производительности, перегрузке процессора СУБД и даже к зависанию всей системы.

  2. Использование Системных полей СКД. В Системе компоновки данных можно использовать стандартное поле СистемныеПоля.НомерПоПорядку. Это работает быстро, но применимо исключительно при выводе данных в отчеты компоновки и бесполезно при разработке бизнес-логики в модулях проведения.
  3. Пост-обработка результата во встроенном языке. Результат запроса выгружался в Таблицу Значений, после чего колонка с номерами заполнялась в цикле Для каждого. Это надежный метод, но он требует перегона всего объема данных на сторону сервера приложений 1С и лишает возможности использовать пронумерованные данные в последующих пакетных запросах СУБД.

Внедрение АВТОНОМЕРЗАПИСИ() перенесло задачу нумерации на уровень СУБД (где она транслируется в эффективные нативные инструкции), что позволило обрабатывать миллионы строк за доли секунды.

Взаимодействие с Дата-акселератором

Механизм Дата-акселератора (используемый для аналитических расчетов больших объемов данных в оперативной памяти) на первых этапах имел жесткое ограничение: он не умел обрабатывать запросы, содержащие одновременно обращение к табличным частям объектов и функцию АВТОНОМЕРЗАПИСИ(). В современных версиях платформы это ограничение было успешно преодолено, и работа с автонумерацией поддерживается в полном объеме.

Полезное дополнение: Группирующие наборы (GROUPING SETS) с релиза 8.3.16

Развивая аналитические возможности языка запросов, фирма «1С» в релизе 8.3.16 добавила еще один мощный инструмент агрегации данных — группирующие наборы.

До версии 8.3.16 для получения многомерных итогов по разным разрезам (например, когда в одном результате нужно получить продажи одновременно по комбинации «Номенклатура + Склад», просто по «Номенклатуре», просто по «Складу» и общий итог) приходилось писать несколько запросов с последующим объединением через тяжелую конструкцию ОБЪЕДИНИТЬ ВСЕ.

Начиная с релиза 8.3.16, конструкция ГРУППИРОВАТЬ ПО поддерживает расширения:

Проанализируем пример использования группирующих наборов:


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

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

Выводы и рекомендации

Подведем итог нашему разбору:

  1. Использовать функцию АВТОНОМЕРЗАПИСИ() можно без опасений, если вы работаете на платформе версии 8.3.13.1513 и выше.
  2. Никогда не закладывайте в логику приложения жесткую привязку к тому, что автонумерация во временной таблице начнется с единицы. Если вам важен точный отсчет от 1 до N (например, для стыковки строк), выполняйте нумерацию на стороне встроенного языка 1С после выгрузки результата запроса или используйте возможности СКД.
  3. Используйте связку АВТОНОМЕРЗАПИСИ() во временных таблицах и GROUPING SETS (доступных с версии 8.3.16) для построения высокопроизводительных аналитических алгоритмов без перегрузки СУБД.
← На главную