Что такое lateral join, как он работает и его плюсы и минусы
Что проверяют
Пишете ли вы SQL руками и понимаете ли, как база выполняет коррелированный подзапрос. У разработчика на Go вопрос обычно вырастает из практики: запрос в цикле по строкам через database/sql или pgx и попытка свести всё к одному обращению.
Как отвечать
Обычный подзапрос в FROM видит только то, что написано внутри него. LATERAL снимает это ограничение: подзапрос получает доступ к столбцам источников левее и вычисляется заново для каждой их строки. По сути это цикл внутри запроса.
select u.id, p.title, p.created_at
from users u
left join lateral (
select title, created_at
from posts
where posts.user_id = u.id
order by created_at desc
limit 3
) p on true;Три последних поста каждого пользователя одним запросом. Без LATERAL это оконная функция с фильтром по row_number(), что читается хуже и на выборке немногих строк из большой группы часто проигрывает.
Плюсы: убирает N+1 из кода Go, разрешает свои LIMIT и ORDER BY на каждую строку, дружит с функциями, возвращающими множество строк (unnest, jsonb_to_recordset). Минусы: план почти всегда вложенный цикл, и на большой левой стороне подзапрос выполнится столько же раз. В SQL Server тот же смысл несут CROSS APPLY и OUTER APPLY.
Где спотыкаются
Пишут join lateral ... on true там, где нужен left join lateral, и молча теряют строки, для которых подзапрос ничего не вернул. Это самая частая правка на ревью.
Приводят пример, где конструкция не нужна. Если внутри нет ни LIMIT, ни агрегата на строку, обычное соединение сделает то же самое и получит лучший план.
Не смотрят план выполнения. Приём убирает N+1 на уровне сети, но не на уровне базы: без индекса по колонке связи и по колонке сортировки внутри окажется сортировка целой группы на каждую строку, и запрос станет хуже цикла в коде.