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

Что такое индексация в БД?

2.3 Middle🔥 171 комментариев
#Базы данных и SQL#Кэширование и производительность

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

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

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

Что такое индексация в БД

Индексация — это механизм оптимизации базы данных, который существенно ускоряет выполнение запросов путём создания специальной структуры данных для быстрого поиска.

Основная идея

Индекс похож на оглавление в книге. Вместо того чтобы читать все 1000 страниц, вы смотрите оглавление и сразу переходите на нужную страницу.

-- Без индекса: должны проверить все 1М строк
SELECT * FROM users WHERE email = 'john@example.com';
-- Time: 5000ms (полная таблица)

-- С индексом: находим мгновенно
CREATE INDEX idx_users_email ON users(email);
SELECT * FROM users WHERE email = 'john@example.com';
-- Time: 10ms (через индекс)

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

Без индекса (Sequential Scan):

Таблица users:
[id=1] [id=2] [id=3] [id=4] ... [id=1000000]

Поиск email='john@example.com':
Проверить id=1? Нет
Проверить id=2? Нет
Проверить id=3? Нет
... проверить все 1М строк ...
Найдено на строке 500000
Время: O(n) — линейное

С индексом (B-Tree поиск):

Индекс (B-Tree):
           Root
          /    \
        A-M    N-Z
       /  |    |  \
      a  b j  n  z
      ↓  ↓ ↓  ↓  ↓
    [rows with matching email]
    
Поиск email='john@example.com':
Шаг 1: Начальный узел, 'j' в диапазоне N-Z? Да
Шаг 2: Перейди в узел N-Z
Шаг 3: Найди лист с 'j'
Шаг 4: Перейди к строкам в таблице
Время: O(log n) — логарифмическое

Типы индексов

1. Primary Key Index (по умолчанию B-Tree)

CREATE TABLE users (
  id INT PRIMARY KEY,  -- автоматически создаёт индекс
  name VARCHAR(100)
);

-- Очень быстрый поиск по id
SELECT * FROM users WHERE id = 123;  -- O(log n)

2. Простой индекс (Single Column Index)

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_id ON orders(user_id);

-- Ускоряет WHERE и JOIN по этому полю
SELECT * FROM users WHERE email = 'john@example.com';
SELECT * FROM orders WHERE user_id = 5;

3. Составной индекс (Composite Index)

CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);

-- Помогает этому запросу
SELECT * FROM orders 
WHERE user_id = 5 AND created_at > '2024-01-01';

-- Важен порядок! (user_id должен быть первым для фильтрации)
-- Может помочь и этому
SELECT * FROM orders WHERE user_id = 5;

-- Но НЕ поможет этому (user_id не первый)
SELECT * FROM orders WHERE created_at = '2024-01-01';

4. Unique Index

CREATE UNIQUE INDEX idx_users_email_unique ON users(email);

-- Гарантирует уникальность
INSERT INTO users (email) VALUES ('john@example.com');
INSERT INTO users (email) VALUES ('john@example.com');  -- ERROR

5. Full Text Index

CREATE FULLTEXT INDEX idx_articles_content ON articles(title, content);

-- Поиск текста (работает в MySQL/PostgreSQL)
SELECT * FROM articles WHERE MATCH(title, content) AGAINST('search query');

6. Partial Index (PostgreSQL)

CREATE INDEX idx_orders_active ON orders(id) 
WHERE status = 'active';

-- Индекс только для активных заказов
-- Меньше место на диске и быстрее вставка

Плюсы индексов

1. Ускорение поиска (главный плюс)

// Запрос становится в 100-1000 раз быстрее
const users = await db.query(
  'SELECT * FROM users WHERE email = ?',
  [email]
);
// С индексом: 10ms
// Без индекса: 5000ms

2. Ускорение JOIN

SELECT u.name, COUNT(o.id) 
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.country = 'RU'
GROUP BY u.id;

-- Индекс на orders.user_id ускоряет JOIN
CREATE INDEX idx_orders_user_id ON orders(user_id);

3. Ускорение SORT и GROUP BY

SELECT * FROM orders ORDER BY created_at LIMIT 10;
-- Индекс на created_at позволяет получить 10 последних за O(10) вместо O(n)

CREATE INDEX idx_orders_created_at ON orders(created_at DESC);

Минусы индексов

1. Требует дополнительное место на диске

TABLE size: 1GB
INDEX size: 500MB (50% от таблицы)
-- Каждый индекс занимает место

2. Замедляет INSERT, UPDATE, DELETE

INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
-- БД должна обновить все индексы, содержащие email
-- 5 индексов = 5 раз больше работы на вставку

3. Требует обслуживания

-- Индексы могут фрагментироваться
REINDEX TABLE users;  -- PostgreSQL
OPTIMIZE TABLE users; -- MySQL

Best Practices

1. Индексируйте колонки в WHERE

-- часто используется в WHERE
SELECT * FROM users WHERE status = 'active';
CREATE INDEX idx_users_status ON users(status);

-- часто используется в WHERE
SELECT * FROM posts WHERE user_id = ? AND created_at > ?;
CREATE INDEX idx_posts_user_date ON posts(user_id, created_at);

2. Индексируйте колонки в JOIN

CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_products_category_id ON products(category_id);

3. Не индексируйте всё подряд

-- Плохо: индекс на редко используемое поле
CREATE INDEX idx_users_created_at ON users(created_at);
-- Если это поле редко используется в WHERE, индекс не поможет

-- Хорошо: анализируйте slow queries
SELECT * FROM users WHERE created_at = ?;  -- часто?
ENABLE slow_query_log;

4. Используйте EXPLAIN для анализа

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

-- Результат с индексом:
-- Index Scan using idx_users_email

-- Результат без индекса:
-- Seq Scan on users (sequential scan — плохо!)

5. Порядок в составных индексах важен

CREATE INDEX idx_bad ON orders(created_at, user_id);
-- Помогает WHERE created_at = ?
-- НЕ помогает WHERE user_id = ?

CREATE INDEX idx_good ON orders(user_id, created_at);
-- Помогает WHERE user_id = ?
-- Помогает WHERE user_id = ? AND created_at > ?
-- Помогает WHERE user_id = ? (prefix search)

Пример оптимизации

// Было: 5000ms (без индексов)
const orders = await db.query(`
  SELECT u.name, COUNT(o.id) as order_count
  FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  WHERE u.country = 'RU' AND u.status = 'active'
  GROUP BY u.id
  ORDER BY order_count DESC
  LIMIT 100
`);

// Добавляем индексы
CREATE INDEX idx_users_country_status ON users(country, status);
CREATE INDEX idx_orders_user_id ON orders(user_id);

// Стало: 100ms (с индексами — 50x быстрее!)

Резюме

Индексы — это критически важный инструмент оптимизации БД. Они могут сделать запрос в 100-1000 раз быстрее, но требуют внимательного анализа и планирования. Всегда используйте EXPLAIN для проверки и не индексируйте случайно.

Что такое индексация в БД? | PrepBro