В запросе трижды решается одна задача удаления дублей: GROUP BY, DISTINCT и ROW_NUMBER. Сначала проверьте уникальность ключей, затем уберите лишние операции.
Дан sql запрос, написанный аналитиком.
В запросе трижды решается одна задача удаления дублей: GROUP BY, DISTINCT и ROW_NUMBER. Сначала проверьте уникальность ключей, затем уберите лишние операции.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Дан sql запрос, написанный аналитиком. Необходимо определить неоптимальности в запросе и предложить как их избежать. В запросе джойнятся две таблицы:
- таблица фактов events с ключом event_id
- таблица-справочник источников трафика с ключом referer_str
Обе таблицы содержат миллиарды записей.
select * from (select distinct e.event_id, e.user_id, e.category_id, e.location_id, s.source_name, s.medium_name, s.campaign_name, row_number() over(partition by e.event_id, e.user_id, e.category_id, e.location_id, s.source_name, s.medium_name, s.campaign_name) as rnk from events e left join traffic_source s on e.referer_str = s.referer_str where e.event_date = current_date() - 1 group by 1,2,3,4,5,6,7) t where rnk = 1
Ответ
В запросе трижды решается одна задача удаления дублей: GROUP BY, DISTINCT и ROW_NUMBER. Сначала проверьте уникальность ключей, затем уберите лишние операции.
GROUP BY уже оставляет одну строку на набор семи полей, поэтому последующий ROW_NUMBER по тем же полям везде даёт 1, а DISTINCT ничего не добавляет. Если event_id и referer_str действительно уникальны, достаточно:
SELECT e.event_id, e.user_id, e.category_id, e.location_id,
s.source_name, s.medium_name, s.campaign_name
FROM events e
LEFT JOIN traffic_source s ON s.referer_str = e.referer_str
WHERE e.event_date = CURRENT_DATE - INTERVAL '1 day';
Это вариант для PostgreSQL с колонкой типа date. Если справочник версионный, сначала выберите нужную версию по явному правилу: DISTINCT не должен маскировать ошибочный join. Для миллиардов строк проверьте отсечение партиций по дате, статистику и стратегию соединения. Такой справочник нельзя автоматически считать маленьким и делать broadcast.