Вопросы по теме «JOIN и кардинальность»
Что произойдёт при JOIN, если в правой таблице несколько строк на один ключ? Сколько строк вернёт LEFT JOIN, если совпадений нет? На собеседовании дают две таблицы и просят предсказать результат без выполнения запроса. Понимание кардинальности при JOIN — навык, который отличает аналитика, способного писать корректные запросы.
Всего в этом разделе 20 вопросов. Каждый — с правильным ответом и кратким разбором теории. Разбито на 4 части по 5 вопросов.
Вопросы 1–5 из 20
1В `events(user_id, event_id)` у пользователя может быть много строк, и в `orders(user_id, order_id)` тоже много строк. Вы соединяете их по `user_id`. Какая `cardinality` получается на ключе и как это влияет на строки?
AЭто `many-to-many`: строки по каждому `user_id` перемножаются, возможен `join explosion`
BЭто `one-to-one`: по каждому `user_id` будет ровно одна строка
CЭто `one-to-many`: число строк станет равно числу пользователей
DЭто `one-to-one`, если добавить `distinct`
Ответ: Два источника, где по ключу много строк, при `JOIN` дают `many-to-many` и риск `join explosion`.
Если у пользователя 5 событий и 2 заказа, после `JOIN` получится 10 строк только для него. Это и есть `duplication`, которая ломает `COUNT(*)`, `SUM()` и даже `AVG()` при неверном уровне анализа. Чтобы избежать, выбирают правильный ключ соединения или делают `pre-aggregate` до нужной гранулярности.
2Вы сделали `LEFT JOIN` `users` → `events` по `user_id`, чтобы сохранить пользователей без событий. Как корректно посчитать количество пользователей на соединённой таблице, не попав в ловушку `duplication`?
AИспользовать `COUNT(DISTINCT user_id)`
BИспользовать `COUNT(*)`, так как это `LEFT JOIN`
CИспользовать `COUNT(event_id)`, чтобы учесть пользователей без событий
DИспользовать `SUM(event_id)`
Ответ: После `LEFT JOIN` к `one-to-many` источнику пользователи дублируются, поэтому для количества пользователей нужен `distinct` по `user_id`.
`LEFT JOIN` сохраняет всех пользователей, но добавляет по строке на каждое совпавшее событие, создавая `duplication`. `COUNT(*)` в таком датасете будет ближе к числу событий, а `COUNT(event_id)` игнорирует строки без событий, где справа `NULL`. `COUNT(DISTINCT user_id)` вернёт число уникальных пользователей, включая тех, у кого справа `NULL`.
3После `JOIN` `users` с `events` по `user_id` (`one-to-many`) вы хотите получить число пользователей, у которых был хотя бы один ивент. Какой расчёт даст корректное число пользователей?
A`COUNT(*)` на результате `JOIN`
B`COUNT(DISTINCT user_id)` на результате `JOIN`
C`SUM(event_id)` на результате `JOIN`
D`AVG(event_id)` на результате `JOIN`
Ответ: В `one-to-many` `JOIN` для подсчёта пользователей нужен `distinct` по `user_id`, иначе вы считаете ивенты.
Каждый пользователь с несколькими событиями даст несколько строк после `JOIN` — это `duplication`. `COUNT(*)` в таком датасете измеряет количество строк, а не количество пользователей. Чтобы считать пользователей, используйте `COUNT(DISTINCT user_id)` или заранее `pre-aggregate` события до одного флага на `user_id`.
4Вы хотите добавить к `orders` атрибут `category` из таблицы `products(product_id, category)` и не изменить количество строк заказов. Что важнее всего проверить про `products`, чтобы избежать `duplication`?
AЧто в `orders` нет повторяющихся `order_id`
BЧто в `products` `product_id` уникален, то есть `one-to-one` `cardinality` по `product_id`
CЧто `category` заполнен на 100%
DЧто вы используете `distinct` после `JOIN`
Ответ: Если справочник имеет `one-to-one` `cardinality` по ключу, атрибутный `JOIN` не вызывает `duplication` строк.
Проблемы начинаются, когда в справочнике на один `product_id` несколько строк, например разные версии атрибутов. Тогда один заказ начинает матчиться на несколько строк и появляется `duplication`. Проверка уникальности ключа — простой способ предсказать изменение числа строк ещё до расчёта метрик.
5В `orders` 120 строк (по одной на `order_id`). В `order_items` ровно по 3 строки на каждый `order_id`. Сколько строк будет после соединения `orders` → `order_items` по `order_id` и почему?
A360, потому что это `one-to-many` и строк станет столько же, сколько в `order_items`
B120, потому что `JOIN` не меняет число строк
C3, потому что на заказ три позиции
D480, потому что 120 + 360
Ответ: При `one-to-many` `JOIN` количество строк обычно становится равным числу строк в «многой» стороне.
Каждая строка из `orders` соединится с 3 строками из `order_items`, поэтому получится 120 * 3 = 360 строк. Это нормальное поведение по `cardinality` и не является ошибкой само по себе. Ошибка появляется, если после такого `JOIN` считать метрики, которые должны быть на уровне заказа, без учёта `duplication`.
Хотите тренировать интерактивно?
В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.
Тренировать в Telegram