При разработке запросов к базам данных нередко возникает ситуация, когда необходимо получить реквизит связанной сущности второго уровня (разыменовать поле «через две точки»). Например, из основной таблицы пакетов мы получаем данные ключа, а из таблицы ключей нам требуется извлечь тип записи. Разберем по шагам, как правильно конструировать подобные запросы, нужно ли использовать вложенные конструкции и как обеспечить высокую производительность при обработке миллионов строк.
СУБД не ограничивает разработчика связыванием только с ведущей (первой) таблицей в секции FROM. Каждое последующее соединение (LEFT JOIN, INNER JOIN) может ссылаться на поля любой из ранее объявленных в запросе таблиц.
Посмотрим на пример построения последовательного соединения трех таблиц:
SELECT
CurrentPackages.ID,
Tab_Key.ID AS KeyID,
Tab_Type.Name AS RecordTypeName
FROM CurrentPackages
LEFT JOIN KeyValues AS Tab_Key
ON (CurrentPackages.ID_Key = Tab_Key.ID
AND CurrentPackages.ID_Source = Tab_Key.ID_Source
AND CurrentPackages.ID_Destination = Tab_Key.ID_Destination)
LEFT JOIN RecordType AS Tab_Type
ON (Tab_Key.ID_Type = Tab_Type.ID)
В данном примере таблица RecordType (псевдоним Tab_Type) соединяется непосредственно с таблицей KeyValues (псевдоним Tab_Key) по полю ID_Type. Заворачивать запрос во вложенные подзапросы для этой цели не требуется — оптимизатор СУБД корректно выстроит дерево выполнения запроса.
Если мы работаем с платформой 1С:Предприятие, обращение к реквизитам через точку (например, Документ.Контрагент.ОсновнойДоговор.ВалютаВзаиморасчетов) на уровне СУБД автоматически разворачивается в аналогичную цепочку неявных LEFT JOIN. Однако здесь важно учитывать следующее поведение:
CASE. Чтобы избежать деградации производительности, необходимо явно ограничивать тип функцией ВЫРАЗИТЬ(Поле КАК Тип).ЛЕВОЕ СОЕДИНЕНИЕ или ВНУТРЕННЕЕ СОЕДИНЕНИЕ в тексте запроса дает разработчику полный контроль над планом запроса, в отличие от неявных точек в секции ВЫБРАТЬ.Когда таблицы содержат миллионы записей, прямое соединение может выполняться медленно, если не соблюдены ключевые правила проектирования:
ID, ID_Type, а также поля составных условий (ID_Source, ID_Destination) должны входить в соответствующие индексы. Для составных условий порядок полей в индексе должен соответствовать принципу селективности: наиболее уникальные поля размещаются первыми.Table Scan / Index Scan).ПОМЕСТИТЬ и выполнять явное индексирование через ИНДЕКСИРОВАТЬ ПО. Вложенные запросы в соединениях скрывают статистику от оптимизатора СУБД, что на миллионных массивах приводит к выбору неоптимального типа соединения (например, ошибочный Nested Loops вместо Hash Match).ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN). Это позволяет СУБД гибко переставлять порядок связывания таблиц для минимизации стоимости плана.