Веб-версияОткрыть в Telegram

ПостПочему порядок колонок в составном индексе важен!

18 сентября 2026
S
SQL Ready | Базы Данных
Почему порядок колонок в составном индексе важен! Составной индекс часто создают, когда запрос фильтрует данные сразу по нескольким колонкам. Но просто добавить нужные поля в индекс недостаточно — их порядок влияет на то, какую часть индекса PostgreSQL сможет эффективно использовать. Есть таблица: CREATE TABLE orders ( id BIGINT, user_id BIGINT, status VARCHAR(20), created_at TIMESTAMPTZ, amount NUMERIC(12,2) ); Допустим, часто выполняется запрос: SELECT id, created_at, amount FROM orders WHERE user_id = 1500 AND created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00' ORDER BY created_at; Для него можно создать составной индекс: CREATE INDEX idx_orders_user_created ON orders (user_id, created_at); Здесь порядок колонок выбран не случайно. Для многоколоночного B-tree наиболее эффективно работают условия равенства по ведущим колонкам, после которых может использоваться диапазонное условие по следующей колонке. B-tree позволяет сначала ограничить сканируемую часть индекса конкретным user_id: user_id = 1500 После этого created_at задаёт диапазон уже внутри записей этого пользователя: created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00' Такой порядок также соответствует ORDER BY created_at: при фиксированном user_id PostgreSQL может получить строки из индекса уже в нужном порядке и при подходящем плане обойтись без отдельной сортировки. Теперь поменяем порядок колонок: CREATE INDEX idx_orders_created_user ON orders (created_at, user_id); Для того же запроса такой индекс обычно менее удачен. Первая колонка используется по диапазону, поэтому PostgreSQL получает диапазон записей за нужный период среди всех пользователей: created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00' Условие по user_id всё ещё может участвовать в индексном сканировании, но уже не сокращает начальный диапазон B-tree так же эффективно, как в варианте (user_id, created_at). Разница особенно заметна, если за выбранный период накопились миллионы заказов разных пользователей. Индекс (user_id, created_at) хорошо подходит и для запроса только по ведущей колонке: WHERE user_id = 1500; А также для сочетания равенства и диапазона: WHERE user_id = 1500 AND created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'; Но запрос только по created_at обычно не получает от этого индекса того же преимущества, поскольку условие на ведущую колонку отсутствует: WHERE created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'; При этом индекс нельзя считать полностью бесполезным: начиная с PostgreSQL 18, в некоторых случаях планировщик может применить B-tree skip scan. Выбор зависит от статистики, количества различных значений ведущей колонки и оценки стоимости плана. Поэтому порядок колонок в составном индексе выбирают под реальные условия запросов, а результат проверяют через план выполнения. EXPLAIN (ANALYZE, BUFFERS) SELECT id, created_at, amount FROM orders WHERE user_id = 1500 AND created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00' ORDER BY created_at; Важно, чтобы практика была показательной, таблица должна содержать достаточно данных, а статистика должна быть актуальной (ANALYZE orders;). На маленькой или пустой таблице PostgreSQL вполне может выбрать Seq Scan, и это будет нормальным поведением оптимизатора. 🔥 Вывод такой: для B-tree индекса (a, b) особенно эффективен сценарий, когда сначала ограничивается ведущая колонка a, а затем используется диапазон по b. Если запрос содержит равенство и диапазон, колонку с равенством часто имеет смысл поставить перед колонкой с диапазоном. Но окончательный выбор индекса должен подтверждаться реальным execution plan. ➡️ SQL Ready | #практика
25 · 2.2K ·

Рядом в ленте

SSQL Ready | Базы Данных🖥 Oracle — агрегация данных и отчётность! Шпаргалка по агрегации данных и формированию отчётности в Oracle SQL: объединение значений с LISTAGG, выбор значений пSSQL Ready | Базы ДанныхФотография
это сообщение
SSQL Ready | Базы Данных🤔 MentorData — материалы по SQL и аналитике данных! Авторский блог с материалами для тех, кто изучает SQL, аналитику данных и готовится к работе в этой сфере. ОSSQL Ready | Базы ДанныхРазворачивайте несколько массивов вместе! Когда приложение передаёт несколько связанных массивов, не нужно отдельно делать unnest(), нумеровать элементы и потом
SSQL Ready | Базы ДанныхSQL Ready | Базы Данных@sql_ready · канал · Технологии
17 466подписчиков1 922средний охват поста
Лента площадки Открыть в Telegram

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Чего мы не делаем · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем