Сортировка результата запроса 1С 8.3 без потери скорости

· 11 мин

Содержание

Чтобы упорядочить запрос в 1С, в конце текста запроса пишут УПОРЯДОЧИТЬ ПО Поле1 УБЫВ, Поле2. Направление по умолчанию — ВОЗР. Если поле ссылочное и нужен «человеческий» порядок по наименованию или дате, добавьте после списка полей АВТОУПОРЯДОЧИВАНИЕ или сортируйте явно по Поле.Наименование.

Частое заблуждение: «раз записи и так приходят по порядку, сортировка не нужна». Без УПОРЯДОЧИТЬ ПО порядок строк в 1С не гарантирован. Сегодня в файловой базе строки идут по коду, завтра на SQL-сервере они придут в порядке, удобном плану запроса. Для производительности важно другое: сортировать по полям, под которые есть индекс, и не сортировать то, что сортировать не нужно.

Всё ниже относится к языку запросов платформы 8.3 и одинаково для БП 3.0, ЗУП 3.1, УТ 11 и любых других конфигураций.

Как упорядочить результат запроса: синтаксис и порядок секций

Предложение УПОРЯДОЧИТЬ ПО стоит в конце пакета одного запроса: после ГДЕ, СГРУППИРОВАТЬ ПО, ИМЕЮЩИЕ и перед ИТОГИ.

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

Что здесь происходит:

  • 🔹 строки сортируются сначала по наименованию по возрастанию;
  • 🔹 при одинаковом наименовании — по артикулу по убыванию;
  • 🔹 в списке можно указывать псевдонимы из ВЫБРАТЬ (Наименование) или полные пути к полям (Номенклатура.Наименование);
  • 🔹 сортировать можно и по полю, которого нет в списке выборки, если запрос без группировки.

Направление и типы значений

Тип поляКак идёт ВОЗР
Числоот меньшего к большему
Датаот ранней к поздней
Булевосначала Ложь, потом Истина
Строкапо алфавиту, правила сравнения задаёт СУБД
Ссылка без автоупорядочиванияпо внутреннему представлению ссылки, не по алфавиту

Строковые коды сортируются как строки. Код "10" окажется раньше кода "2". Если коды справочника хранятся строкой без ведущих нулей, нужный порядок даст только числовое поле или выражение ВЫРАЗИТЬ.

Конструктор запроса

В конструкторе сортировка задаётся на вкладке Порядок. Перетащите поля из левой колонки в правую и выберите направление в колонке «Сортировка». Флажок «Автоупорядочивание» на той же вкладке добавляет в текст ключевое слово АВТОУПОРЯДОЧИВАНИЕ.

Упорядочивание с ИТОГИ и ОБЪЕДИНИТЬ

  • 📌 В запросе с ИТОГИ сортировка работает внутри каждой группировки итогов. Строки детальных записей упорядочены внутри своего итога.
  • 📌 В запросе с ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ сортировку пишут один раз, после последней части. Она относится ко всему объединению, а поля берутся по псевдонимам первой части.
ВЫБРАТЬ Поступление.Дата КАК Дата, Поступление.Ссылка КАК Документ
ИЗ Документ.ПоступлениеТоваровУслуг КАК Поступление
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Реализация.Дата, Реализация.Ссылка
ИЗ Документ.РеализацияТоваровУслуг КАК Реализация
УПОРЯДОЧИТЬ ПО
    Дата УБЫВ

АВТОУПОРЯДОЧИВАНИЕ и ИЕРАРХИЯ: как упорядочить запросы по ссылкам

Здесь чаще всего ошибаются те, кто переходит с SQL. Строка УПОРЯДОЧИТЬ ПО Контрагент сортирует не по наименованию контрагента, а по внутреннему значению ссылки. Для пользователя такой порядок выглядит случайным.

Есть три способа получить понятный порядок:

  1. Явное поле: УПОРЯДОЧИТЬ ПО Контрагент.Наименование. Порядок точно предсказуем, но платформа добавит соединение с таблицей справочника.
  2. АВТОУПОРЯДОЧИВАНИЕ: ссылочные поля в списке сортировки заменяются полями, по которым объект упорядочивается по умолчанию. Для справочника это обычно основное представление (код или наименование), для документов — дата.
  3. Сортировка по полю самой таблицы: если в выборке есть Номенклатура.Наименование, сортируйте по нему, а не по Ссылка.Наименование — лишнего разыменования не будет.
ВЫБРАТЬ
    Реализация.Ссылка КАК Документ,
    Реализация.Контрагент КАК Контрагент,
    Реализация.СуммаДокумента КАК Сумма
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
УПОРЯДОЧИТЬ ПО
    Контрагент,
    Документ
АВТОУПОРЯДОЧИВАНИЕ

АВТОУПОРЯДОЧИВАНИЕ удобно в отчётах и обработках «для людей». В служебных запросах, где порядок нужен для алгоритма, лучше писать поля явно: так проще читать текст и предсказывать план.

Сортировка дерева: ИЕРАРХИЯ

Для иерархических справочников и планов счетов есть ключевое слово ИЕРАРХИЯ. Оно выстраивает строки так, чтобы элементы шли сразу после своей группы:

ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Наименование КАК Наименование
ИЗ
    Справочник.Номенклатура КАК Номенклатура
УПОРЯДОЧИТЬ ПО
    Ссылка ИЕРАРХИЯ

ИЕРАРХИЯ применяется только к полю иерархической таблицы. На большом справочнике такая сортировка заметно тяжелее обычной: платформе нужно учитывать родителей на всех уровнях.

Сортировка по составным типам и разыменованным полям

Составной тип — это поле, где может лежать ссылка на разные объекты: Регистратор у регистров, «Документ-основание», реквизит типа «Справочник.Контрагенты, Справочник.ФизическиеЛица».

При сортировке по такому полю значения разных типов не перемешиваются: сначала они группируются по типу, потом упорядочиваются внутри типа. Порядок самих типов задаёт платформа, на него не стоит опираться в алгоритмах.

Главная ловушка: Регистратор.Дата

// Медленно на большой базе
УПОРЯДОЧИТЬ ПО
    Продажи.Регистратор.Дата

Регистратор может ссылаться на десятки видов документов. Чтобы взять у него поле Дата, платформа соединит таблицу регистра с таблицей каждого вида документа-регистратора. Для сортировки миллиона строк это лишние соединения на каждый документ конфигурации.

Как сделать лучше:

  • ✅ сортируйте по Период регистра: он равен дате регистратора и уже есть в таблице;
  • ✅ если нужен именно один вид документа, приведите тип: ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.РеализацияТоваровУслуг).Дата;
  • ✅ для порядка «как в учёте» используйте МоментВремени в документах и регистрах, где это поле есть.

Строки неограниченной длины

Поле типа «Строка» с длиной 0 (неограниченная) нельзя использовать в сортировке, группировке и сравнении. Запрос выдаст ошибку. Выход — привести к ограниченной строке:

УПОРЯДОЧИТЬ ПО
    ВЫРАЗИТЬ(Номенклатура.Комментарий КАК СТРОКА(150))

Поля типа ХранилищеЗначения не сортируются вовсе.

Индексы и скорость упорядочивания запроса в 1С

Сортировка дешёвая, когда СУБД может читать строки уже в нужном порядке — по индексу. Тогда отдельной операции сортировки в плане нет, а ВЫБРАТЬ ПЕРВЫЕ 10 … УПОРЯДОЧИТЬ ПО отдаёт результат почти мгновенно.

Какие индексы есть всегда

ОбъектЧто индексирует платформа без настроек
Справочникссылку, код и наименование
Документссылку, дату вместе со ссылкой, номер
Регистр сведенийизмерения в порядке их следования в конфигураторе, у периодического — вместе с периодом
Регистр накоплениярегистратор и период, таблицы итогов — по измерениям

Отсюда правила:

  • 📈 УПОРЯДОЧИТЬ ПО Дата, Ссылка в документах идёт по индексу;
  • 📈 сортировка по первым измерениям регистра сведений в порядке их объявления быстрее, чем по последним;
  • 📉 сортировка по обычному реквизиту без индекса на большой таблице — это полная сортировка всего результата.

Свойство «Индексировать»

В конфигураторе у реквизита справочника или документа есть свойство «Индексировать» с тремя значениями:

  1. Не индексировать — значение по умолчанию.
  2. Индексировать — индекс по реквизиту и ссылке.
  3. Индексировать с доп. упорядочиванием — в индекс добавляются поля стандартного порядка объекта (у справочника — код или наименование, у документа — дата). Это вариант для динамических списков, где пользователь отбирает по реквизиту и видит строки в привычном порядке.

Индекс ускоряет чтение, но замедляет запись. Не индексируйте всё подряд: каждый индекс увеличивает базу и время проведения документов. Включение индекса в типовой конфигурации — это изменение объекта, которое придётся сохранять при каждом обновлении.

Что ломает использование индекса

  • ❌ сортировка по выражению: УПОРЯДОЧИТЬ ПО ГОД(Дата), ПОДСТРОКА(Наименование, 1, 3);
  • ❌ сортировка по полю через точку из другой таблицы (Товар.Родитель.Наименование);
  • ❌ сортировка по полям в порядке, не совпадающем с индексом (Ссылка, Дата вместо Дата, Ссылка).

Большие выборки: когда сортировка тормозит

Признак проблемы простой: запрос без УПОРЯДОЧИТЬ ПО выполняется за 2 секунды, с ним — за 40. Значит, СУБД сортирует сотни тысяч строк, и результат не помещается в память, отведённую под операцию. В MS SQL такая сортировка уходит в tempdb, в PostgreSQL — во временные файлы на диске.

Приёмы, которые реально помогают

  1. Сортируйте один раз, в конце. УПОРЯДОЧИТЬ ПО во временной таблице (ПОМЕСТИТЬ) и во вложенном запросе не задаёт порядок итогового результата. Он имеет смысл там только вместе с ПЕРВЫЕ N.
  2. Сначала сократите выборку. Отберите и сгруппируйте данные во временную таблицу, а сортируйте уже 500 итоговых строк, а не 500 000 исходных.
  3. Разыменовывайте после сокращения. Поля вида Товар.Наименование берите в последнем запросе пакета, где строк мало.
  4. Не сортируйте то, что потом пересортируют. В системе компоновки данных порядок вывода задаётся в настройках варианта на вкладке «Сортировка». Порядок из текста запроса отчёт не обязан сохранять.
  5. Используйте ПЕРВЫЕ N с индексированным полем. Задача «последние 20 документов» решается как ВЫБРАТЬ ПЕРВЫЕ 20 … УПОРЯДОЧИТЬ ПО Дата УБЫВ и читает 20 строк по индексу, а не всю таблицу.

Пакет: сортировка в конце

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

ВЫБРАТЬ ПЕРВЫЕ 50
    ВТ.Номенклатура КАК Номенклатура,
    ВТ.Номенклатура.Наименование КАК Наименование,
    ВТ.Сумма КАК Сумма
ИЗ
    ВТ_Продажи КАК ВТ
УПОРЯДОЧИТЬ ПО
    Сумма УБЫВ

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

Как найти тяжёлую сортировку

  • 🔍 Замер производительности в конфигураторе (Отладка → Замер производительности) показывает строку кода, на которой выполняется запрос, и долю времени.
  • 🔍 Технологический журнал с событиями DBMSSQL или DBPOSTGRS даёт текст SQL-запроса и длительность; с включённым сбором планов — и план.
  • 🔍 План в СУБД: в MS SQL ищите оператор Sort с большим числом строк и предупреждение о сбросе в tempdb; в PostgreSQL — EXPLAIN (ANALYZE) и строку Sort Method: external merge.

Если в плане видно Sort по миллионам строк перед Top, значит индекса под порядок нет или выражение в УПОРЯДОЧИТЬ ПО мешает его использовать.

Сортировка в разных СУБД: файловая база, MS SQL, PostgreSQL

Платформа переводит запрос 1С в SQL для конкретной СУБД. Логика результата одинакова, но в деталях порядок может различаться.

НюансЧто учесть
Строкиправила сравнения задаёт СУБД; порядок пробелов, знаков препинания и спецсимволов может отличаться между файловой базой и сервером
NULLместо NULL при сортировке не стоит закладывать в алгоритм; заменяйте явно через ЕСТЬNULL
Одинаковые значениястроки с равным ключом сортировки могут прийти в любом порядке, и он может меняться от запуска к запуску
Временные файлыпри нехватке памяти MS SQL использует tempdb, PostgreSQL — временные файлы; медленный диск под ними тормозит все тяжёлые сортировки
Файловая базанет отдельного оптимизатора и планов; большие сортировки упираются в диск и память клиента или сервера 1С

Стабильный порядок при равных значениях

Если в отчёте или выгрузке важно, чтобы строки не «прыгали», добавьте в конец списка уникальное поле:

УПОРЯДОЧИТЬ ПО
    Дата,
    Ссылка

Без Ссылка два документа с одной датой и временем могут поменяться местами при следующем выполнении. Для постраничной выгрузки это приводит к пропущенным и задвоенным строкам.

NULL в левом соединении

После ЛЕВОЕ СОЕДИНЕНИЕ поля правой таблицы могут быть NULL. Чтобы такие строки шли в конце независимо от СУБД, сортируйте по выражению:

УПОРЯДОЧИТЬ ПО
    ВЫБОР
        КОГДА Цены.Цена ЕСТЬ NULL ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ,
    Цены.Цена УБЫВ

Это выражение индекс не использует, поэтому применяйте его на уже сокращённой выборке.

Когда сортировать не в запросе

Иногда упорядочивать запрос вообще не нужно:

  • 🧩 Результат дальше идёт в соединение или временную таблицу — порядок там ничего не даёт.
  • 🧩 Данных мало и их потом пересортирует код. Для таблицы значений на несколько сотен строк хватит метода ТаблицаЗначений.Сортировать("Сумма Убыв, Дата").
  • 🧩 Отчёт на СКД. Задавайте порядок в настройках варианта, чтобы пользователь мог менять его без правки текста.
  • 🧩 Динамический список. Порядок задаёт сам список и пользователь; в тексте запроса списка сортировка обычно лишняя, а для быстрой сортировки по реквизиту ему нужен индекс.

Обратная ситуация: таблицу на 200 000 строк выгружать в память и сортировать в коде не стоит. Это медленнее, чем отдать работу СУБД, и съедает память сервера 1С.

Ошибки при упорядочивании и как их исправить

Диагностика: выберите симптом

Ещё две ошибки, которые не дают сообщения, но дают неверный результат:

  • ⚠️ Сортировка по строковому коду даёт порядок 1, 10, 11, 2, 3. Если нужен числовой порядок, сортируйте по числовому полю или по коду с ведущими нулями.
  • ⚠️ ПЕРВЫЕ N без УПОРЯДОЧИТЬ ПО возвращает любые N строк. На файловой базе это могут быть первые по коду, на сервере — какие угодно. Для «последних», «самых дорогих» и подобных выборок сортировка обязательна.

Частые вопросы

Можно ли сортировать по полю, которого нет в ВЫБРАТЬ?
Да, если в запросе нет группировки. С СГРУППИРОВАТЬ ПО поле должно быть в группировке или внутри агрегатной функции.
Чем ВОЗР отличается от отсутствия направления?
Ничем. ВОЗР — направление по умолчанию, его можно не писать.
Работает ли АВТОУПОРЯДОЧИВАНИЕ без УПОРЯДОЧИТЬ ПО?
Да. Для запроса без явной сортировки платформа сама выберет порядок по полям основной таблицы, например по дате для документов. Но для предсказуемости лучше перечислить поля явно.
Как отсортировать по количеству строк в группе?
Сгруппируйте и добавьте агрегат КОЛИЧЕСТВО(*) КАК ЧислоСтрок, затем УПОРЯДОЧИТЬ ПО ЧислоСтрок УБЫВ.
Почему порядок разный в файловой и серверной базе?
Правила сравнения строк и обработка равных значений зависят от СУБД. Добавьте в сортировку уникальное поле и не опирайтесь на место NULL.