Индексы в SQL: кластеризованные и некластеризованные типы

Если ты хоть раз работал с реляционными базами данных, наверняка слышал про индексы. Но вот чем кластеризованные индексы отличаются от некластеризованных? Зачем вообще заморачиваться их созданием, если всё и так работает? Давай разберёмся — без академической занудности, на пальцах, с примерами и реальными кейсами.

Зачем нужны индексы в SQL

Индексы — это как оглавление в книге: чтобы быстро найти нужную главу, не листая всю книгу подряд. В базах данных индексы ускоряют поиск, сортировку, джоины и вообще любую работу с большими таблицами. Без индексов даже простые запросы могут превратиться в адское тормозное болото.

Но! Индексы — это не магия. Они занимают место, замедляют вставку и обновление данных. Так что важно понимать, когда и какие индексы нужны.

Кластеризованные и некластеризованные индексы — в чём разница?

  • Кластеризованный индекс (Clustered Index) — это способ физической сортировки данных в таблице. В SQL Server или PostgreSQL он обычно совпадает с первичным ключом (PRIMARY KEY). Можно создать только один кластеризованный индекс на таблицу, потому что строки реально лежат на диске в этом порядке.
  • Некластеризованный индекс (Non-Clustered Index) — это отдельная структура, которая указывает, где искать нужные строки. Можно создать сколько угодно некластеризованных индексов, и они не влияют на физический порядок хранения данных.

Что потребуется

  • Любая современная ОС: Linux, Windows, MacOS — не принципиально.
  • СУБД: PostgreSQL (https://www.postgresql.org/download/) или MySQL (https://dev.mysql.com/downloads/), или MSSQL (https://www.microsoft.com/en-us/sql-server/sql-server-downloads). Буду приводить примеры на PostgreSQL, но синтаксис для MySQL и MSSQL похожий.
  • Железо: для тестов хватит даже VPS с 1 ГБ RAM и 1 vCPU. Для реальных проектов — чем больше данных, тем важнее иметь SSD и побольше оперативки.

Установка (пошагово, на примере PostgreSQL)

  1. Установка PostgreSQL
    sudo apt update
    sudo apt install postgresql postgresql-contrib
    

    Для MacOS: brew install postgresql. Для Windows — скачай инсталлятор с официального сайта.

  2. Запуск PostgreSQL и вход в psql
    sudo systemctl start postgresql
    sudo -u postgres psql
    
  3. Создание тестовой базы и таблицы
    CREATE DATABASE testdb;
    \c testdb
    
    CREATE TABLE users (
        id SERIAL PRIMARY KEY,
        username VARCHAR(100) NOT NULL,
        email VARCHAR(100) NOT NULL,
        created_at TIMESTAMP NOT NULL DEFAULT NOW()
    );
    
  4. Вставка тестовых данных
    INSERT INTO users (username, email)
    SELECT
        'user' || i,
        'user' || i || '@mail.com'
    FROM generate_series(1, 100000) AS s(i);
    

Использование: создание и работа с индексами

Проверить существующие индексы

\d users

Видим, что по умолчанию на PRIMARY KEY уже создан кластеризованный индекс.

Создать некластеризованный (обычный) индекс

CREATE INDEX idx_users_email ON users(email);

Теперь поиск по email ускорится:

EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'user50000@mail.com';

Создать составной индекс

CREATE INDEX idx_users_username_email ON users(username, email);

Удалить индекс

DROP INDEX idx_users_email;

Посмотреть все индексы в базе

SELECT * FROM pg_indexes WHERE tablename = 'users';

Создать уникальный индекс

CREATE UNIQUE INDEX idx_users_username_unique ON users(username);

Создать индекс с условием (partial index)

CREATE INDEX idx_users_recent ON users(created_at) WHERE created_at > now() - interval '30 days';

Ошибки и антипаттерны

  • Не создавай индексы на всё подряд. Каждый индекс — это доп. нагрузка на запись и обновление. Индексируй только то, по чему реально ищешь или джоинишь.
  • Не делай слишком широкие составные индексы (на 3+ поля) — чаще всего это избыточно.
  • Не забывай про VACUUM и REINDEX в PostgreSQL — со временем индексы могут фрагментироваться.
  • В MySQL кластеризованный индекс всегда на PRIMARY KEY в InnoDB. Не делай PRIMARY KEY на больших varchar — это плохо для производительности.
  • Не пытайся «оптимизировать» все SELECT’ы индексами — иногда лучше переписать запрос или добавить агрегацию.

Реальный пример из жизни

Однажды пришлось оптимизировать таблицу логов (~50 млн строк) для поиска по user_id и времени. Без индекса — запросы шли по 30-60 секунд. После добавления составного индекса:

CREATE INDEX idx_logs_user_time ON logs(user_id, created_at);

— время упало до 100-200 мс. Но! Индекс занял 5+ ГБ на диске, что для VPS оказалось критично. Пришлось делать партиционирование и хранить свежие логи отдельно. Так что индексы — это не только про скорость, но и про баланс между скоростью, размером и удобством.

Заключение

Индексы — мощный инструмент, но требуют понимания. Кластеризованный индекс определяет физический порядок хранения строк, а некластеризованные — быстрые указатели. Не ленись смотреть официальную документацию PostgreSQL или MySQL и экспериментировать на тестовой базе. Не забывай: всё надо мерить, профилировать и не бояться дропать ненужные индексы!

Хотите прочитать больше про Администрирование?
Отзывов нет.

Ваш отзыв

Пожалуйста, заполните поля снизу и добавьте отзыв!.
Имя *
E-mail *
Сайт
Сообщение *