Кафедра ИТКафедра ИТ
Блог
Обучение
  • О кафедре
  • Направления подготовки
  • Друзья и партнеры
  • Структура кафедры
  • Обращение к студентам
  • Официальный сайт «ВШП»
GitHub
Блог
Обучение
  • О кафедре
  • Направления подготовки
  • Друзья и партнеры
  • Структура кафедры
  • Обращение к студентам
  • Официальный сайт «ВШП»
  • ИТ.03 - 20 - Индексы и производительность в MySQL

  1. Главная
  2. Учебные материалы
  3. ИТ.03 - Основы проектиро...
  4. Индексы и производительн...

ИТ.03 - 20 - Индексы и производительность в MySQL

Примечание

Лекция находится в промежуточном состоянии и будет дорабатываться.

Введение

На прошлом занятии мы разобрали ограничения и целостность данных. Следующий шаг - понять, как сохранять приемлемую скорость запросов при росте объема таблиц.

Главный инструмент на старте этой темы - индексы.

Индекс не меняет сами данные, но меняет способ доступа к ним: MySQL может читать значительно меньше строк, если нужный столбец проиндексирован.

В этой лекции разберем базовую практику:

  • что такое индекс и зачем он нужен;
  • как устроен поиск с индексом и без него;
  • чем отличается уникальный и неуникальный индекс;
  • как в MySQL добавить, посмотреть и удалить индекс;
  • как базово проверить использование индекса через EXPLAIN.

Что такое индекс

Индекс в БД - это специальная структура данных, которая помогает быстрее находить строки по значениям столбцов.

Если очень упрощенно:

  • без индекса MySQL чаще читает таблицу почти целиком;
  • с индексом MySQL может перейти сразу к нужному диапазону строк.

Обычно индексы делают для полей, которые часто участвуют в:

  • WHERE
  • JOIN
  • ORDER BY

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

Без индекса

Сервер перебирает строки одну за другой. Чем больше таблица, тем дольше поиск.

С индексом

Сервер использует индекс и сразу идет в нужную часть данных, поэтому читает меньше строк.


Почему индекс работает быстро

В MySQL обычные индексы устроены как B-Tree (древовидная структура из узлов и уровней).

Простая аналогия: это как оглавление в большой книге.

  • без оглавления пришлось бы листать страницы подряд;
  • с оглавлением мы сначала находим раздел, потом подраздел, и только затем нужную страницу.

С индексом в БД происходит то же самое: MySQL идет по диапазонам ключей сверху вниз и быстро отбрасывает лишние данные.

Структура B-Tree в упрощенном виде:

 B-Tree структура индекса MySQL

Как индекс обычно строится:

 Построение индекса в MySQL

То есть индекс - это не «магия», а отдельная упорядоченная структура, где хранятся ключи и ссылки на строки.

Наглядно (оценка порядка роста числа сравнений):

Количество строкПримерное число сравнений
10~3
100~7
1 000~10
10 000~13
100 000~17
1 000 000~20

Заметка

Эффект максимальный, когда значения в индексируемом поле достаточно разнообразные. Если в поле почти везде одно и то же значение, польза ниже.


Уникальный и неуникальный индекс

Неуникальный индекс

Нужен, чтобы ускорить поиск. Повторяющиеся значения допускаются.

Пример: индекс по city.

Уникальный индекс

Нужен и для скорости, и для контроля уникальности. Дубли запрещены.

Пример: индекс по email.


Наглядные иллюстрации индексов

Сравнение пути выполнения запроса:

 Поиск без индекса и с индексом

Заметка

Смысл: без индекса читаем почти все строки, с индексом идем по короткому маршруту.

Пример с конкретными ID и фамилиями:

 Пример таблицы и индекса по фамилии

Заметка

Таблица хранит строки в своем порядке (здесь по id), а индекс хранит ключи в другом порядке (например по last_name). Поэтому порядок данных и порядок индекса обычно не совпадают.

Пошаговое исключение сегментов при поиске фамилии:

 Пошаговое исключение сегментов при поиске

Короткий разбор примера:

  • выполняем запрос WHERE last_name = 'Сидоров';
  • в индексе находим ключ Сидоров -> id=1;
  • по id=1 переходим к нужной строке таблицы;
  • без индекса пришлось бы проверять много строк подряд.

Учебная база для примеров

Создадим учебную таблицу пользователей и заполним ее данными на 100 человек:

CREATE DATABASE IF NOT EXISTS index_demo;
USE index_demo;

DROP TABLE IF EXISTS users;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  email VARCHAR(255) NOT NULL,
  first_name VARCHAR(100) NOT NULL,
  last_name VARCHAR(100) NOT NULL,
  city VARCHAR(100) NOT NULL,
  age TINYINT UNSIGNED NOT NULL
);

INSERT INTO users (email, first_name, last_name, city, age)
SELECT
  CONCAT('student', LPAD(n, 3, '0'), '@example.com') AS email,
  ELT(1 + ((n - 1) % 10), 'Анна', 'Иван', 'Ольга', 'Петр', 'Мария', 'Сергей', 'Елена', 'Дмитрий', 'Нина', 'Алексей') AS first_name,
  ELT(1 + ((n - 1) % 20), 'Иванов', 'Петров', 'Сидоров', 'Кузнецов', 'Смирнов', 'Попов', 'Васильев', 'Новиков', 'Федоров', 'Морозов', 'Волков', 'Соловьев', 'Лебедев', 'Козлов', 'Николаев', 'Егоров', 'Павлов', 'Семенов', 'Голубев', 'Виноградов') AS last_name,
  ELT(1 + ((n - 1) % 10), 'Москва', 'Казань', 'Томск', 'Пермь', 'Самара', 'Уфа', 'Тула', 'Омск', 'Сочи', 'Тверь') AS city,
  18 + ((n - 1) % 8) AS age
FROM (
  SELECT ones.n + tens.n * 10 + 1 AS n
  FROM (
    SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
    UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
  ) AS ones
  CROSS JOIN (
    SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
    UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
  ) AS tens
) AS seq
WHERE n <= 100;

SELECT COUNT(*) AS total_users FROM users;

Добавление индекса

Неуникальный индекс

ALTER TABLE users
ADD INDEX idx_users_last_name (last_name);

Индекс поможет при частом поиске по last_name.

Уникальный индекс

ALTER TABLE users
ADD UNIQUE INDEX uq_users_email (email);

Теперь значения email не могут повторяться.

Если попытаться вставить дубликат email, MySQL вернет ошибку.


Как посмотреть индексы

SHOW INDEX FROM users;

Эта команда показывает:

  • имя индекса;
  • по какому столбцу он построен;
  • уникальный индекс или нет.

Как удалить индекс

ALTER TABLE users
DROP INDEX idx_users_last_name;

Удалять индексы полезно, если они больше не нужны и только замедляют запись.


Как быстро проверить, что индекс используется

Для базовой проверки используется EXPLAIN.

EXPLAIN
SELECT *
FROM users
WHERE last_name = 'Иванов';

Для старта достаточно смотреть три поля:

  • type - способ доступа к данным;
  • key - какой индекс выбрал MySQL;
  • rows - сколько строк MySQL ожидает прочитать.

Совет

Если после создания индекса в key появилось имя этого индекса, обычно это хороший признак, что индекс задействован.


В чем отличие от SQLite

Синтаксис создания индекса похож, но поведение СУБД не одинаковое.

Инфо

В SQLite индексы есть и они работают. Но SQLite обычно применяют в локальных/встраиваемых сценариях, а не в больших многопользовательских БД. Поэтому в курсе детальный разбор производительности сделан на MySQL, при этом различия по индексам между SQLite и MySQL важно учитывать.

ВопросMySQLSQLite
Архитектурасерверная СУБДвстраиваемая СУБД (файл)
Проверка планаEXPLAINEXPLAIN QUERY PLAN
Основной контекст использованиямногопользовательские серверные системылокальные/встраиваемые решения

Практический вывод:

  • одинаковый SQL не гарантирует одинаковую скорость;
  • после переноса запроса между SQLite и MySQL план нужно проверять заново.

Частые ошибки при работе с индексами

  • Добавлять индексы «на все столбцы подряд».
  • Не проверять результат через EXPLAIN.
  • Индексировать поля, по которым почти нет фильтрации.
  • Забывать, что каждый индекс замедляет INSERT и UPDATE.

Практические рекомендации

  • Добавляйте индекс только под реальные частые запросы.
  • Начинайте с полей из WHERE, JOIN, ORDER BY.
  • Для уникальных данных (email, guid) используйте UNIQUE.
  • После добавления индекса всегда делайте быструю проверку EXPLAIN.

Самопроверка

Практические задания

Задание 1. Неуникальный индекс

Условие

В базе index_demo сравните план запроса до и после добавления индекса на city:

SELECT *
FROM users
WHERE city = 'Москва';

Сравните в EXPLAIN поля key и rows.

Решение
EXPLAIN
SELECT *
FROM users
WHERE city = 'Москва';

ALTER TABLE users
ADD INDEX idx_users_city (city);

EXPLAIN
SELECT *
FROM users
WHERE city = 'Москва';

Задание 2. Уникальный индекс

Условие

Добавьте уникальный индекс на email, затем попробуйте вставить дубликат email.

Решение
ALTER TABLE users
ADD UNIQUE INDEX uq_users_email (email);

INSERT INTO users (email, first_name, last_name, city, age)
VALUES ('student001@example.com', 'Анна', 'Иванова', 'Москва', 19);

Ожидаемый результат: ошибка из-за нарушения уникальности.

Задание 3. Просмотр и удаление индекса

Условие
  1. Посмотрите список индексов таблицы users.
  2. Удалите индекс idx_users_city.
  3. Снова посмотрите список индексов.
Решение
SHOW INDEX FROM users;

ALTER TABLE users
DROP INDEX idx_users_city;

SHOW INDEX FROM users;

Полезные ссылки

  • MySQL 8.4 Reference Manual - Optimization and Indexes
  • MySQL 8.4 Reference Manual - EXPLAIN Statement
Последнее обновление: 24.02.2026, 22:37
Предыдущая
ИТ.03 - 19 - Ограничения и целостность данных в MySQL
© Кафедра информационных технологий ЧУВО «ВШП», 2026. Версия: 0.35.12
Материалы доступны в соответствии с лицензией: