Индекс по няколко колони
Накратко: Съставният индекс е индекс по няколко колони, който помага, когато заявката ползва колоните му отляво надясно.
Проблем
Последните десет
Страницата „Наскоро разглеждани“ показва последните 10 посещения на клиента, от най-новото. Индексът по customer_id вече е направен. Виж плана:
Индексът намира 60-те посещения, но не ги дава подредени по дата. Базата ги сортира сама (USE TEMP B-TREE). При клиент с хиляди посещения това е най-бавната част, а от всичките трябват само 10.
Идеята
Две колони в един индекс
Индексът може да е по няколко колони: CREATE INDEX име ON таблица(колона1, колона2). Това е индекс по няколко колони (composite index). Подреден е като телефонен указател: първо по фамилия, а при еднаква фамилия по име.
Индексът по (customer_id, seen_at) е подреден първо по клиент, а посещенията на един клиент са подредени по дата. Базата намира клиента и чете датите му отзад напред. Сортиране не трябва:
Същият индекс помага и когато условието е по двете колони. Базата отива на клиента и в неговата част търси от датата нататък:
И само по първата колона, все едно е индекс само по customer_id:
Пробвай
Посещенията за период
Отделът за обслужване често пита колко пъти клиентът е гледал продукти от дадена дата нататък. Направи индекс само по тези две колони, с който заявката е SEARCH и по клиента, и по датата.
Решение
CREATE INDEX idx_visits_customer_seen ON visits(customer_id, seen_at);CREATE INDEX idx_visits_customer_seen ON visits(customer_id, seen_at); Редът на колоните е важен: първо тази със =, после тази с >=. Проверката гледа кои колони са в индексите на visits и в какъв ред, затова името е по твой избор.
Виж го
Отляво надясно
Със същия индекс отчетът по дни пита само за датата:
Планът е SCAN. Пише USING COVERING INDEX, защото COUNT(*) се смята от индекса, но базата пак чете всичките 300 000 записа в него. Пусни самата заявка и виж времето:
В телефонния указател не можеш да намериш всички с име „Мария“, без да прочетеш целия указател. Имената са подредени само вътре във всяка фамилия.
Това е правилото отляво надясно: индекс по (a, b) помага за условия по a, по a и b, и за ORDER BY b, когато a е дадено с =. За условие само по b не помага. Ако не си сигурен, провери с EXPLAIN QUERY PLAN.
Идеята
Цената на индекса
Индексите не са безплатни. Всеки нов ред трябва да се впише на правилното място във всеки индекс на таблицата. Двете полета добавят по 100 000 посещения. Първото е без индекси, второто с четири. Пусни ги и сравни времената:
Същото е при UPDATE на индексирана колона и при DELETE.
Индексите заемат и място. SQLite пази базата на страници от по 4 096 байта, а pragma_page_count() казва колко са страниците. Ето базата без индекси и с четирите:
С четирите индекса базата е над три пъти по-голяма. Затова се слагат индекси за заявките, които наистина имаш, а не за всяка колона „за всеки случай“.
По-точно, за любопитните
Вторият индекс от четирите, (customer_id, seen_at), прави първия, (customer_id), излишен: по правилото отляво надясно той върши и неговата работа. Такива двойки се срещат често и рядко се забелязват. PostgreSQL пази колко пъти е ползван всеки индекс (pg_stat_user_indexes), така че неползваните могат да се намерят.
Упражнение
Две задачи
1. В базата има индекс по (customer_id) и индекс по (customer_id, seen_at). Махни излишния.
Махни индекса, чиято работа върши другият:
Решение
DROP INDEX idx_visits_customer;DROP INDEX idx_visits_customer; Индексът по (customer_id, seen_at) върши и търсенето само по клиент. Обратното не е вярно: индексът само по клиент не помага за подредбата по дата.
2. Индексът по (customer_id, seen_at) е направен. Покажи датите на последните 3 посещения на клиент 1234, от най-новото.
Последните 3 дати на посещение на клиент 1234:
Решение
SELECT seen_at FROM visits
WHERE customer_id = 1234
ORDER BY seen_at DESC LIMIT 3;WHERE customer_id = 1234 ORDER BY seen_at DESC LIMIT 3. Излизат 2026-10-10 и два пъти 2026-09-20: в този ден клиентът е отворил страницата два пъти. С индекса базата намира клиента, чете три записа отзад напред и спира.
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: Агрегатни функции: COUNT, SUM, AVG · INSERT: нови редове · Индекси · EXPLAIN: планът на заявката
- Продължава в: Бавни заявки
- Задачи по темата: Индекси и скорост