Индексы и планы запросов — Примеры
Пример 1 — Поиск вместо сканирования
Список заказов фильтруется по клиенту и сортируется по дате, и по мере роста таблицы он становится медленнее; план ниже — то, что движок выбрал для этого запроса. Определите способ доступа, напишите индекс, который его заменит, и скажите, как вы докажете изменение.
select id, total from orders
where customer_id = 7 order by placed_at desc limit 20;
QUERY PLAN (пояснительно)
Sort (rows=4200000)
-> Seq Scan on orders (rows=4200000)
Filter: (customer_id = 7)
Rows Removed by Filter: 4199994
Решение
create index orders_customer_placed_idx
on orders (customer_id, placed_at desc);
-- сначала равенство по customer_id, затем столбец, по которому идёт сортировка
Движок прочитал каждую строку и отбросил почти все. Однако индекс держит заказы одного клиента именно в том порядке, который просит запрос: он переходит к этому клиенту и читает двадцать строк, и этап сортировки исчезает вместе с ними. Доказывать изменение лучше сравнением числа прочитанных строк до и после, а не затраченным временем — быстрая машина скрывает сканирование большой таблицы. Обычно же ошибаются, добавляя индекс и оставляя рядом другой, которым не может воспользоваться ни один запрос: каждая запись от этого дорожает.
Пример 2 — Индекс в неверном порядке
Для экрана заказов добавили составной индекс, а отчёт по диапазону дат всё равно сканирует всю таблицу. Напишите индекс, которым отчёты действительно смогут воспользоваться, и скажите, что произойдёт с тем, который добавили.
create index orders_status_placed_idx on orders (status, placed_at);
-- the report:
select id, total from orders
where placed_at >= date '2026-01-01'
order by placed_at;
Решение
create index orders_placed_idx on orders (placed_at);
drop index orders_status_placed_idx; -- после проверки, что им никто не пользуется
Индекс по двум столбцам в таком порядке обслуживает фильтр по первому столбцу или по обоим вместе, но на фильтр отчёта по второму в одиночку он эффективно ответить не может. К тому же у столбца status мало различных значений, так что поиск по нему всё равно вернул бы большую долю таблицы. Проверять, какие индексы ещё используются, и убирать лишние так же полезно, как добавлять тот, которого не хватает, — каждый индекс замедляет каждую вставку. Обычно же ошибаются, добавляя индекс за индексом, пока планировщику не из чего выбирать: это стоит записи и даёт ложное чувство безопасности.