NodeJS Back-end Инженер

NodeJS Back-end Инженер

Роадмап навыков для прокачки

Что такое Index?

DatabasesSQLConstraints

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

Index (индекс) — это специальная структура данных, которая ускоряет поиск записей в таблице, работая подобно алфавитному указателю в книге: вместо перебора всех страниц вы сразу находите нужный раздел.

Ключевые аспекты

  • Ускорение SELECT — поиск по индексированной колонке в разы быстрее
  • Дополнительное хранилище — индекс занимает место на диске
  • Замедление записи — при INSERT/UPDATE/DELETE индексы нужно обновлять
  • B-tree структура — большинство индексов используют сбалансированное дерево

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

  • Драматическое ускорение запросов SELECT с WHERE
  • Ускорение ORDER BY и GROUP BY
  • Ускорение JOIN операций
  • Обеспечение уникальности (UNIQUE INDEX)

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

  • Занимают дисковое пространство
  • Замедляют операции вставки и обновления
  • Требуют обслуживания (фрагментация)
  • Избыточные индексы вредят производительности

Частые ошибки на собеседованиях

  • Считают, что индексы только ускоряют — они также замедляют запись
  • Создают индексы на все колонки — это плохая практика
  • Забывают про составные индексы — порядок колонок в них важен
  • Не понимают, что PRIMARY KEY автоматически создаёт индекс

Введение и проблематика

Представьте таблицу с миллионом записей. Без индекса каждый запрос SELECT * FROM users WHERE email = 'john@example.com' потребует проверки каждой строки — это называется Full Table Scan. С индексом база данных находит нужную запись практически мгновенно.

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

Почему это критически важно?

ОперацияБез индексаС индексом
Поиск 1 записи в 1 млн~500 мс~1 мс
СложностьO(n)O(log n)
Чтение с дискаВсёТолько нужное

Базовая теория

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

Большинство индексов используют структуру B-tree (сбалансированное дерево):

graph TD A[Корень: 50] --> B[Узел: 25] A --> C[Узел: 75] B --> D[Лист: 10, 15, 20] B --> E[Лист: 30, 35, 40] C --> F[Лист: 60, 65, 70] C --> G[Лист: 80, 85, 90]

Запрос: найти запись с id = 65

База данных начинает с корня (50). 65 > 50, идём вправо.

Переход к узлу 75

65 < 75, идём влево к листу (60, 65, 70).

Находим значение

Лист содержит 65 и указатель на строку таблицы. Готово за 3 шага вместо проверки всех записей!

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

ТипОписаниеКогда использовать
B-treeСтандартный, для сравнений и диапазоновПо умолчанию для большинства случаев
HashТолько для точного совпадения (=)Когда нужен только поиск по равенству
Full-textПолнотекстовый поискПоиск по тексту
SpatialГеопространственные данныеКоординаты, геометрия

Практические примеры

Создание индексов

sql
-- Создаём индекс на колонку email
CREATE INDEX idx_users_email ON users(email);
 
-- Теперь этот запрос работает быстро
SELECT * FROM users WHERE email = 'john@example.com';
 
-- Удаление индекса
DROP INDEX idx_users_email ON users;

Проверка использования индекса

sql
-- EXPLAIN показывает план выполнения запроса
EXPLAIN SELECT * FROM users WHERE email = 'john@example.com';
 
-- Результат (с индексом):
-- | type  | key              | rows |
-- | ref   | idx_users_email  | 1    |
 
-- Результат (без индекса):
-- | type  | key  | rows    |
-- | ALL   | NULL | 1000000 |  -- Full Table Scan!

Пограничные кейсы

⚠️

Индекс не всегда используется! Оптимизатор может решить, что Full Scan быстрее.

Когда индекс не помогает

sql
-- 1. Функции на индексированной колонке
SELECT * FROM users WHERE LOWER(email) = 'john@example.com';
-- Индекс на email НЕ используется!
 
-- Решение: функциональный индекс (MySQL 8.0+, PostgreSQL)
CREATE INDEX idx_users_email_lower ON users((LOWER(email)));
 
-- 2. Оператор LIKE с % в начале
SELECT * FROM users WHERE email LIKE '%@gmail.com';
-- Индекс НЕ используется!
 
-- Работает с индексом:
SELECT * FROM users WHERE email LIKE 'john%';
 
-- 3. Неравенство на первой колонке составного индекса
-- Индекс: (status, created_at)
SELECT * FROM orders WHERE status != 'completed' AND created_at > '2024-01-01';
-- Индекс используется неэффективно

Когда слишком много индексов — плохо

sql
-- Каждый INSERT должен обновить ВСЕ индексы
CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(255),
    category_id INT,
    price DECIMAL(10,2),
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    status INT
);
 
-- Плохо: индекс на каждую колонку
CREATE INDEX idx_1 ON products(name);
CREATE INDEX idx_2 ON products(category_id);
CREATE INDEX idx_3 ON products(price);
CREATE INDEX idx_4 ON products(created_at);
CREATE INDEX idx_5 ON products(updated_at);
CREATE INDEX idx_6 ON products(status);
 
-- INSERT теперь обновляет 7 индексов (включая PK)!
🚫

Избыточные индексы замедляют INSERT, UPDATE, DELETE и занимают место на диске. Создавайте индексы только для часто используемых запросов.


Влияние на производительность

Чтение vs Запись

graph LR A[Без индексов] --> B[SELECT: медленно] A --> C[INSERT: быстро] D[С индексами] --> E[SELECT: быстро] D --> F[INSERT: медленнее]
ОперацияБез индексаС 1 индексомС 5 индексами
SELECT500 мс1 мс1 мс
INSERT1 мс2 мс6 мс
UPDATE1 мс3 мс8 мс

Рекомендации по созданию индексов

Создавайте индексНе создавайте индекс
Колонки в WHEREРедко используемые колонки
Колонки в JOINМаленькие таблицы (< 1000 строк)
Колонки в ORDER BYКолонки с низкой кардинальностью
Foreign keysЧасто обновляемые колонки

Плюсы и минусы

АспектПлюсыМинусы
ЧтениеДраматическое ускорение
ЗаписьЗамедление
ПамятьДополнительное место
УникальностьГарантия через UNIQUE
ОбслуживаниеНужна дефрагментация

Вопросы интервьюера

Q: Всегда ли индекс ускоряет запросы?

Нет. Для маленьких таблиц Full Scan может быть быстрее. Оптимизатор сам решает, использовать ли индекс.

Q: Создаётся ли индекс автоматически для PRIMARY KEY?

Да, PRIMARY KEY автоматически создаёт уникальный индекс. То же для UNIQUE constraint.

Q: Почему порядок колонок в составном индексе важен?

Индекс (A, B) эффективен для запросов с WHERE A=... или WHERE A=... AND B=..., но не для WHERE B=... (B не первая колонка).

Q: Когда использовать UNIQUE INDEX вместо обычного?

Когда нужно гарантировать уникальность значений: email, username, номер заказа.


Источники