> В каком порядке строить составной индекс для user_id и даты (Python)
Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы
Компании: Notamedia, Точка
Стек: Python
> Пример ответа
Короткий ответ
Порядок колонок в составном индексе определяется паттерном запросов: сначала колонка с условием равенства (=), затем - с диапазоном или сортировкой. Для user_id и даты чаще всего правильный порядок - (user_id, date), так как типичный запрос фильтрует по конкретному пользователю и затем сортирует или ограничивает по дате. Если же запросы часто идут по диапазону дат без привязки к пользователю, индекс (date, user_id) может быть оправдан, но это редкий случай.
Подробное объяснение
Составной индекс в B-tree работает как упорядоченный список по всем колонкам слева направо. Это означает, что:
- Индекс
(user_id, date)эффективен для запросов видаWHERE user_id = ? AND date > ?,WHERE user_id = ? ORDER BY date,WHERE user_id = ?. - Индекс
(date, user_id)эффективен дляWHERE date BETWEEN ? AND ? AND user_id = ?только если фильтр поuser_idприменяется после сужения по дате - но в этом случае БД сможет использовать индекс только для первой колонки, аuser_idбудет фильтроваться как post-filter.
Ключевой принцип: первая колонка должна быть селективной (с высокой кардинальностью) и использоваться в условиях равенства. Если первая колонка - дата, а запросы всегда фильтруют по user_id, индекс будет бесполезен для таких запросов, потому что БД не сможет пропустить диапазон дат без учёта пользователя.
Дополнительные соображения:
- Если нужна сортировка по дате в обратном порядке, индекс
(user_id, date DESC)может быть создан отдельно, но обычно достаточно(user_id, date)- БД умеет сканировать в обратном направлении. - Если запросы включают
dateвORDER BYиLIMIT, индекс(user_id, date)позволяет избежать filesort. - Если запросы часто агрегируют по пользователю за период, индекс
(user_id, date)также помогает с covering index, если добавить нужные колонки вINCLUDE.
На практике
Для типового backend-приложения с таблицей событий или заказов:
- Основной запрос: "все записи пользователя за последний месяц" →
(user_id, date). - Запрос "последние N записей пользователя" →
(user_id, date)сORDER BY date DESC LIMIT N. - Запрос "все пользователи, активные в определённый день" →
(date, user_id)- но это редкий аналитический сценарий.
Если в таблице есть и другие частые фильтры (например, status), стоит рассмотреть отдельные индексы или включить status в индекс после user_id, но перед датой - только если он используется как равенство.
Пример кода
SQL-- Основной индекс для типового сценарияCREATE INDEX idx_user_date ON events (user_id, date);-- Запрос, который использует индекс полностьюSELECT *FROM eventsWHERE user_id = 123AND date >= '2025-01-01'ORDER BY dateLIMIT 100;-- Если нужен covering index для частого запросаCREATE INDEX idx_user_date_covering ON events (user_id, date)INCLUDE (event_type, payload);
Как отвечать на собеседовании
Начни с вопроса: "Какие запросы преобладают?" - это показывает, что ты не даёшь шаблонный ответ. Затем объясни принцип: первая колонка - для равенства, вторая - для диапазона или сортировки. Приведи пример типичного запроса и покажи, как индекс ускоряет его. Упомяни, что порядок можно проверить через EXPLAIN - если видишь Using filesort или Using where после index scan, значит порядок неоптимален. Заверши trade-off: если есть редкий запрос по дате без user_id, можно добавить отдельный индекс (date), а не менять порядок основного.
Что проверяет интервьюер
- Понимание внутреннего устройства B-tree индекса и ограничения на префиксное использование колонок.
- Умение связывать структуру индекса с реальными паттернами запросов.
- Способность рассуждать о trade-off между разными порядками колонок.
- Знание, как проверить эффективность индекса (EXPLAIN, покрывающие индексы).
- Понимание разницы между условием равенства и диапазоном.
Типичные ошибки
- Ответ "всегда ставь user_id первым" без анализа запросов - это не универсальное правило.
- Утверждение, что индекс
(date, user_id)подойдёт для запроса поuser_id- не подойдёт, если фильтр по дате не ограничивает диапазон. - Игнорирование сортировки: если нужен
ORDER BY date DESC, индекс(user_id, date)работает, но если нуженORDER BY user_id, date DESC- потребуется отдельный индекс. - Предложение менять порядок колонок в существующем индексе без учёта других запросов, которые его используют.
- Забывание про covering index - в некоторых случаях можно избежать чтения таблицы целиком.
> Похожие задачи по Python
Как происходит передача аргументов в функцию в Python
Что такое coroutine и как он работает в Python
Что такое контейнеризация и зачем она нужна
Для чего нужны фикстуры в pytest
> Похожие задачи по backend
В чем разница между процессом и потоком и какова их иерархия?
Что такое coroutine и как он работает в Python
Что такое контейнеризация и зачем она нужна
Для чего нужны фикстуры в pytest
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью