Вопрос о производительности иерархических справочников часто встречается на собеседованиях для разработчиков 1С уровня Middle и Senior. На первый взгляд он кажется абстрактным, но за ним стоит глубокое понимание того, как метаданные 1С транслируются в физические таблицы СУБД и как платформа оптимизирует работу с древовидными структурами. Рассмотрим подробно ситуацию, когда у нас есть два идентичных по количеству элементов справочника (один с ограничением в 7 уровней, другой — без), и выясним, какой из них будет работать быстрее при обращении к элементу на 3-м уровне вложенности.
Для начала проанализируем, как иерархия хранится в базе данных. Независимо от того, стоит ли в конфигураторе флаг «Ограничение уровней» или нет, платформа 1С использует классическую модель Adjacency List (список смежности). Рассмотрим структуру таблицы на уровне SQL:
В обоих случаях в таблице справочника будет присутствовать поле _ParentIDRRef (ссылка на родителя). Никаких дополнительных полей «Уровень» или «Путь до корня» в физической таблице по умолчанию не создается. Индексация также идентична: платформа автоматически создает индекс по полям Parent + Ref, что позволяет быстро находить подчиненные элементы для конкретного узла.
Следовательно, если мы выполняем прямой запрос к элементу по его ссылке, например:
ВЫБРАТЬ
Спр.Наименование
ИЗ
Справочник.Тестовый КАК Спр
ГДЕ
Спр.Ссылка = &Ссылка
Разницы в производительности не будет абсолютно никакой. СУБД выполнит поиск по первичному ключу (Clustered Index Seek), и наличие настроек иерархии в метаданных никак не повлияет на план запроса.
Ситуация кардинально меняется, когда мы начинаем работать с иерархическими связями. Разберем по шагам, как платформа 1С обрабатывает условие В ИЕРАРХИИ. Проанализируем ситуацию: нам нужно найти все дочерние элементы для узла 3-го уровня.
Для справочника с ограниченной иерархией (например, 7 уровней) платформа заранее «знает» максимально возможную глубину дерева. Это теоретически позволяет ей сформировать один SQL-запрос с фиксированным количеством соединений таблицы самой с собой (LEFT JOIN). Например, для 3-х уровней это могло бы выглядеть как цепочка соединений по полю _ParentID.
Для справочника с неограниченной иерархией платформа не может предсказать глубину. В старых версиях платформы или при определенных условиях 1С использует итерационный подход:
Однако в современных версиях платформы и для современных СУБД (MS SQL, PostgreSQL) 1С старается использовать рекурсивные запросы (CTE — Common Table Expressions). Но даже здесь наличие жесткого ограничения в 7 уровней в метаданных может подсказать оптимизатору платформы более эффективный способ построения текста запроса.
В языке запросов 1С существует возможность получить уровень элемента. Важно понимать, что это поле виртуальное. Рассмотрим, что происходит при обращении к нему:
ВЫБРАТЬ
Спр.Ссылка,
Спр.Уровень() КАК УровеньЭлемента
ИЗ
Справочник.Тестовый КАК Спр
Поскольку в таблице SQL нет колонки Level, платформе приходится вычислять её «на лету». Это делается путем обхода дерева вверх до родителя, у которого поле _ParentID равно NULL (пустая ссылка). Если иерархия ограничена 7 уровнями, алгоритм поиска корня имеет жесткий предел. Для неограниченного справочника теоретически проверка может длиться дольше, если данные в базе некорректны (например, возникло зацикливание, хотя платформа 1С старается этого не допускать при записи).
Проанализируем результаты замеров из практики (сообщение 3 в обсуждении), где неограниченный справочник показал большую скорость. На первый взгляд это парадокс, но он имеет техническое объяснение. Выясним причину:
При записи и чтении объектов с ограниченной иерархией движок 1С выполняет дополнительные программные проверки. Платформа должна контролировать, чтобы при интерактивном переносе элемента или программной записи не был превышен лимит в 7 уровней. Эти проверки встроены в объектную модель СправочникОбъект и в механизмы работы файловой СУБД.
В случае с неограниченной иерархией часть этих проверок в программном коде платформы просто отсутствует (пропускается). В масштабе миллионов операций или при специфических замерах в Технологическом журнале это может дать микросекундное преимущество справочнику без ограничений, так как «лишний» код по контролю лимита не исполняется.
Подведем итог нашего исследования. Если на собеседовании задают такой вопрос, правильным подходом будет уточнение контекста запроса:
1. Если это простой запрос (выборка по ссылке): Разницы в производительности нет, так как структура индексов и таблиц в SQL идентична.
2. Если используется оператор В ИЕРАРХИИ: Справочник с ограничением (7 уровней) может быть быстрее в серверном варианте, так как платформа может построить более предсказуемый и оптимизированный план SQL-запроса с ограниченным числом соединений.
3. Если оценивается общая работа системы (включая запись): Справочник с неограниченной иерархией может работать чуть быстрее из-за отсутствия накладных расходов на программный контроль лимита уровней со стороны платформы 1С.
4. Влияние уровня расположения: Тот факт, что элемент находится именно на 3-м уровне, в данном случае нивелирует разницу между 7 и "бесконечностью", так как в обоих случаях глубина поиска (3 шага) одинакова. Основное влияние оказывают именно настройки метаданных, заставляющие платформу выбирать тот или иной алгоритм трансляции запроса в SQL.