SQL*PostgreSQL*Базы данных*Разработка бэкенда*Сложность: Junior

Наглядный гайд по SQL JOIN: шпаргалка с примерами, нюансами NULL и планами запросов

Подробный разбор INNER, LEFT, RIGHT, FULL и CROSS JOIN. Разбираемся, как базы данных выполняют соединения под капотом (Nested Loop, Hash Join, Merge Join).

Команда Capycodio
Команда Capycodio
·7 мин

Вопрос о типах объединения таблиц (JOIN) — абсолютная классика любого технического интервью для бэкендеров, системных аналитиков, тестировщиков и дата-инженеров.

На собеседовании кандидату редко дают идеальные данные: почти всегда добавляют NULL, дубликаты ключей и просят объяснить, как движок СУБД (PostgreSQL или MySQL) будет выполнять этот запрос на миллионах строк.

В этой статье мы структурируем все виды JOIN на наглядных данных, разберем коварные ловушки с NULL и заглянем под капот алгоритмов соединения.


Исходные данные для примеров#

Для демонстрации возьмем две простые таблицы:

Таблица developers (Разработчики):

ТаблицаСвайп вправо
idnameteam_id
1Антон10
2Лена20
3ДенисNULL

Таблица teams (Команды):

ТаблицаСвайп вправо
idtitle
10Backend
20Frontend
30DevOps

Обратите внимание: разработчик Денис ещё не распределен в команду (team_id = NULL), а в команде DevOps пока нет ни одного сотрудника.


1. INNER JOIN (Внутреннее соединение)#

Возвращает строки только тогда, когда условие соединения истинно для обеих таблиц одновременно.

SQL
SELECT 
    d.name, 
    t.title AS team_name
FROM developers d
INNER JOIN teams t ON d.team_id = t.id;

Результат:#

ТаблицаСвайп вправо
nameteam_name
АнтонBackend
ЛенаFrontend
  • Денис отфильтрован, так как NULL = 10 дает UNKNOWN.
  • Команда DevOps отфильтрована, так как на неё никто не ссылается.

2. LEFT OUTER JOIN (Левое соединение)#

Возвращает все строки из левой таблицы, дополняя их данными из правой таблицы. Если совпадения нет — поля правой таблицы заполняются NULL.

SQL
SELECT 
    d.name, 
    t.title AS team_name
FROM developers d
LEFT JOIN teams t ON d.team_id = t.id;

Результат:#

ТаблицаСвайп вправо
nameteam_name
АнтонBackend
ЛенаFrontend
ДенисNULL
💡
Классическая задача с собеседования

Вопрос: Как найти всех разработчиков, у которых нет команды?
Решение: Используйте LEFT JOIN с фильтрацией WHERE t.id IS NULL:

SQL
SELECT d.name
FROM developers d
LEFT JOIN teams t ON d.team_id = t.id
WHERE t.id IS NULL;

3. FULL OUTER JOIN (Полное внешнее соединение)#

Объединяет результаты LEFT и RIGHT JOIN. В результирующую выборку попадают все строки из обеих таблиц. Если совпадения нет с любой из сторон — подставляется NULL.

SQL
SELECT 
    d.name, 
    t.title AS team_name
FROM developers d
FULL OUTER JOIN teams t ON d.team_id = t.id;

Результат:#

ТаблицаСвайп вправо
nameteam_name
АнтонBackend
ЛенаFrontend
ДенисNULL
NULLDevOps

4. CROSS JOIN (Декартово произведение)#

Соединяет каждую строку первой таблицы с каждой строкой второй таблицы. Количество строк в результате равно произведению строк исходных таблиц ($3 \times 3 = 9$).

SQL
SELECT d.name, t.title
FROM developers d
CROSS JOIN teams t;
⚠️
Опасность на проде

Случайный CROSS JOIN (или забытое условие ON в устаревшем синтаксисе FROM table1, table2) на таблицах по 100 000 строк породит выборку из 10 миллиардов строк и положит память сервера БД.


5. Как СУБД выполняет JOIN под капотом?#

На Middle+ собеседовании вас обязательно спросят: «Как планировщик PostgreSQL выбирает алгоритм соединения?».

Существует три основных алгоритма:

  1. Nested Loop (Вложенные циклы):
    • Для каждой строки внешней таблицы ищется совпадение во внутренней таблице.
    • Идеален, когда одна из таблиц очень мала, либо для второй таблицы есть индекс по внешнему ключу.
  2. Hash Join (Хеш-соединение):
    • СУБД строит в оперативной памяти хеш-таблицу по меньшей таблице, затем сканирует вторую таблицу и проверяет наличие ключей в хеше.
    • Используется для больших неотсортированных объемов данных при соединении по равенству (=).
  3. Merge Join (Соединение слиянием):
    • Обе таблицы сортируются по ключу соединения, после чего движок параллельно идет по двум отсортированным спискам.
    • Самый быстрый алгоритм для огромных объемов, если данные уже отсортированы (например, по индексу B-Tree).

Сводная таблица типов соединений#

ТаблицаСвайп вправо
Тип JOINЧто попадает в результатЧто будет при отсутствии пары
INNERТолько совпадения с обеих сторонСтрока отбрасывается
LEFTВсе из левой таблицы + совпадения справаПоля справа = NULL
RIGHTВсе из правой таблицы + совпадения слеваПоля слева = NULL
FULLВсе строки из обеих таблицNULL на несовпадающей стороне
CROSSКаждая строка с каждой (декартово произведение)

Резюме#

Понимание физических планов (EXPLAIN ANALYZE) и поведения NULL при соединениях таблиц — ключевой навык для проектирования быстрых запросов в реляционных базах данных.

Capycodio

Прокачивай IT-скиллы с Capycodio

Не зубри теорию часами перед компьютером. Короткие 3-минутные интерактивные сессии прямо с телефона: по дороге, за кофе или перед сном.

Теги публикации:
#sql#postgresql#join#собеседование#оптимизация
Капибара
Команда Capycodio

Мы создаем интерактивный мобильный тренажер для разработчиков. Короткие сессии по 3-5 минут, чтобы держать базу и закрывать пробелы перед собеседованиями.