← Назад к вопросам

Как работают индексы в базах данных?

2.0 Middle🔥 201 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Индексы в Базах Данных

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

Как работает индекс

// БЕЗ индекса (полный scan таблицы)
SELECT * FROM users WHERE email = 'john@example.com';
// БД проверяет ВСЕ 1000000 строк: O(n)

// С индексом (быстрый поиск)
CREATE INDEX idx_email ON users(email);
SELECT * FROM users WHERE email = 'john@example.com';
// БД ищет в индексе: O(log n)

Основные типы индексов

B-Tree индекс (самый частый)

CREATE INDEX idx_name ON users(name);
CREATE INDEX idx_created_at ON users(created_at);

-- Используется для: =, <, >, <=, >=, BETWEEN, LIKE
SELECT * FROM users WHERE name LIKE 'John%';
SELECT * FROM users WHERE created_at > '2024-01-01';

Составной индекс (несколько колонок)

CREATE INDEX idx_user_role ON users(user_id, role);

-- Помогает для запросов
SELECT * FROM users WHERE user_id = 5 AND role = 'admin';

Уникальный индекс (PRIMARY KEY, UNIQUE)

CREATE UNIQUE INDEX idx_email ON users(email);
-- или
ALTER TABLE users ADD UNIQUE(email);

-- Гарантирует отсутствие дубликатов
INSERT INTO users (email) VALUES ('john@example.com'); -- OK
INSERT INTO users (email) VALUES ('john@example.com'); -- Ошибка!

Полнотекстовый индекс (FULLTEXT)

CREATE FULLTEXT INDEX idx_content ON posts(title, content);

-- Поиск по словам
SELECT * FROM posts WHERE MATCH(title, content) AGAINST('php backend');

Производительность

Без индекса (Full Table Scan)

$start = microtime(true);
$results = $pdo->query("SELECT * FROM users WHERE email = 'john@example.com'")->fetchAll();
$time = microtime(true) - $start;
echo $time; // 2.5 секунды для 10 млн строк

С индексом (Index Seek)

CREATE INDEX idx_email ON users(email);

$start = microtime(true);
$results = $pdo->query("SELECT * FROM users WHERE email = 'john@example.com'")->fetchAll();
$time = microtime(true) - $start;
echo $time; // 0.001 секунды! 2500x быстрее

Когда создавать индексы

Индексируй колонки:

  • В WHERE условиях (SELECT * FROM users WHERE email = ...)
  • В JOIN условиях (ON users.id = orders.user_id)
  • В ORDER BY (ORDER BY created_at DESC)
  • В GROUP BY (GROUP BY category)
  • Первичные ключи (PRIMARY KEY)
  • Внешние ключи (FOREIGN KEY)
-- Хорошие кандидаты на индексы
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_order_user ON orders(user_id);
CREATE INDEX idx_post_created ON posts(created_at);
CREATE INDEX idx_product_category ON products(category);

НЕ индексируй:

  • Колонки с низкой селективностью (много одинаковых значений)
  • Маленькие таблицы (< 1000 строк)
  • Колонки, которые редко используются в запросах
  • Очень большие TEXT/BLOB колонки

Составные индексы (важно!)

-- Порядок колонок имеет значение
CREATE INDEX idx_user_role_active ON users(user_id, role, is_active);

-- Работает хорошо
SELECT * FROM users WHERE user_id = 5;
SELECT * FROM users WHERE user_id = 5 AND role = 'admin';
SELECT * FROM users WHERE user_id = 5 AND role = 'admin' AND is_active = 1;

-- Не использует индекс!
SELECT * FROM users WHERE role = 'admin'; -- Первая колонка не в условии
SELECT * FROM users WHERE is_active = 1; -- Пропустили role

Проблемы индексов

1. Замедление INSERT/UPDATE/DELETE

// Без индексов
INSERT INTO users (name, email) VALUES ('John', 'john@example.com'); // быстро

// С индексами
CREATE INDEX idx_email ON users(email);
CREATE INDEX idx_name ON users(name);
INSERT INTO users (name, email) VALUES ('John', 'john@example.com'); // медленнее
// БД должна обновить оба индекса!

2. Избыточные индексы

-- Избыточно
CREATE INDEX idx_email ON users(email);
CREATE INDEX idx_email_name ON users(email, name); -- Первый индекс не нужен

3. Фрагментация индекса

-- Много DELETE/UPDATE может привести к фрагментации
ALTER TABLE users ENGINE=InnoDB; -- Перестроить таблицу
-- или
OPTIMIZE TABLE users; -- Оптимизировать

Анализ индексов

-- Посмотреть использует ли запрос индекс
EXPLAIN SELECT * FROM users WHERE email = 'john@example.com';

-- Результат:
-- type: const/eq_ref (хорошо, использует индекс)
-- type: range (норм)
-- type: ALL (плохо, full table scan)

-- Показать индексы таблицы
SHOW INDEXES FROM users;

-- Показать статистику индексов
SELECT * FROM information_schema.STATISTICS WHERE TABLE_NAME = 'users';

Лучшие практики

  • Создавай индексы на колонках в WHERE — это главное
  • Порядок в составных индексах — сначала колонки без range
  • Не переиндексируй — каждый индекс замедляет INSERT/UPDATE
  • Удаляй неиспользуемые индексы — они занимают место
  • Проверяй EXPLAIN — смотри как работают твои запросы
  • Мониторь performance — следи за slow query логом
Как работают индексы в базах данных? | PrepBro