При написании запросов в системе «1С:Предприятие» разработчики часто сталкиваются с задачей исключения дублирующихся строк из результата выборки. Для этого платформа предоставляет два основных инструмента: использование ключевого слова РАЗЛИЧНЫЕ (аналог DISTINCT в SQL) и секцию СГРУППИРОВАТЬ ПО (аналог GROUP BY). На первый взгляд они кажутся взаимозаменяемыми, но так ли это на самом деле? В этой статье мы подробно разберем, какой вариант работает быстрее, проанализируем результаты практических замеров и выясним, в каких ситуациях следует отдавать предпочтение конкретному методу.
Рассмотрим ситуацию, когда перед разработчиком стоит задача получить уникальный список регистраторов из крупного регистра накопления. Проанализируем пример запроса, с которого началось обсуждение:
ВЫБРАТЬ
ПартииТоваровОрганизаций.Регистратор КАК Ссылка
ИЗ
РегистрНакопления.ПартииТоваровОрганизаций КАК ПартииТоваровОрганизаций
ГДЕ
// некие условия
УПОРЯДОЧИТЬ ПО
Ссылка
АВТОУПОРЯДОЧИВАНИЕ
Для выяснения истины были проведены замеры в консоли запросов на реальных данных. Выясним, как ведут себя эти операторы при разном объеме записей:
РАЗЛИЧНЫЕ и СГРУППИРОВАТЬ ПО время выполнения составило около 1 секунды для обоих вариантов. Разница оказалась практически неощутимой.РАЗЛИЧНЫЕ, в другом — СГРУППИРОВАТЬ ПО.Проанализировав эти данные, мы можем сделать вывод, что с точки зрения "чистой" скорости выполнения на современных СУБД разница между этими операторами находится в пределах погрешности. Это происходит потому, что оптимизаторы SQL-серверов (MS SQL Server, PostgreSQL) зачастую трансформируют DISTINCT в GROUP BY еще на этапе подготовки плана запроса.
Чтобы понять, почему производительность идентична, разберем внутренние механизмы работы СУБД. Существует два основных способа, которыми сервер баз данных устраняет дубликаты:
Stream Aggregate: Этот метод используется, если данные уже отсортированы (например, выборка идет по индексированному полю). СУБД просто проходит по списку и пропускает повторяющиеся значения. Это самый эффективный сценарий для обоих операторов.
Hash Match: Если данные не отсортированы, СУБД строит в оперативной памяти временную хэш-таблицу, куда помещает уникальные ключи. При обработке каждой новой строки проверяется ее наличие в хэш-таблице. В этом случае и РАЗЛИЧНЫЕ, и СГРУППИРОВАТЬ ПО потребляют одинаковое количество ресурсов процессора и памяти.
Несмотря на схожесть в производительности, существуют критические различия в синтаксисе и возможностях работы с данными. Рассмотрим их подробнее:
Поля неограниченной длины: В языке запросов 1С наложено ограничение на использование строк неограниченной длины и полей типа ХранилищеЗначения. Мы не можем использовать РАЗЛИЧНЫЕ, если в списке ВЫБРАТЬ есть такие поля. Аналогично, их нельзя включить в секцию СГРУППИРОВАТЬ ПО. Однако, если нам нужно получить уникальные ссылки и при этом вывести описание (строку), мы можем использовать группировку с агрегатной функцией:
ВЫБРАТЬ
Номенклатура.Ссылка,
МАКСИМУМ(Номенклатура.НаименованиеПолное) КАК Описание
ИЗ
Справочник.Номенклатура КАК Номенклатура
СГРУППИРОВАТЬ ПО
Номенклатура.Ссылка
Оператор РАЗЛИЧНЫЕ не позволяет применять такие трансформации данных "на лету" в рамках одного уровня запроса.
Проанализируем правила сортировки. При использовании РАЗЛИЧНЫЕ стандарт требует, чтобы все поля, указанные в секции УПОРЯДОЧИТЬ ПО, обязательно присутствовали в списке ВЫБРАТЬ. Если вы попытаетесь отсортировать результат по полю, которое не выбрано, запрос вернет ошибку. В случае с СГРУППИРОВАТЬ ПО правила работы с выражениями в сортировке могут быть более гибкими в зависимости от версии платформы и настроек СУБД.
Рассмотрим важный нюанс, упомянутый опытными разработчиками. Существует риск получить неожиданный результат при использовании сложных запросов с объединениями. Если в запросе присутствует инструкция ОБЪЕДИНИТЬ ВСЕ, использование РАЗЛИЧНЫЕ может привести к появлению дублей, если логика объединения была сложной и РАЗЛИЧНЫЕ применилось не к итоговому результату, а к одной из частей. В таких случаях группировка итоговой таблицы во временной таблице или во внешнем запросе является более надежным и предсказуемым решением.
Выясним, как правильно выбирать между этими инструментами с точки зрения стандартов разработки:
Проанализировав ситуацию, мы можем дать следующие рекомендации:
ГДЕ.СГРУППИРОВАТЬ ПО могло не поддерживаться в определенных контекстах, хотя в современных конфигурациях на базе 8.3 это ограничение практически нивелировано.Таким образом, выбор между этими двумя конструкциями — это в первую очередь вопрос стиля кодирования и решаемой логической задачи, а не вопрос производительности системы.