Методическое руководство для преподавателя

Дисциплина: «ОП.08 Основы проектирования баз данных» — Тема 3. Этапы проектирования баз данных — Практическое занятие №6: ключевые поля, индексы, связи (Занятие №18)

1. Регламент и хронометраж учебного занятия

Занятие рассчитано на 2 академических часа. Ниже приведен детальный поминутный тайминг для основного регламента (80 минут) и сокращенного расписания (60 минут).

Этап занятия 80 минут (основной) 60 минут (сокращенный) Ключевой фокус этапа
1. Организационный момент и постановка инженерной проблемы 5 минут 3 минуты Кейс «Падение интернет-банкинга при формировании выписок за месяц»
2. Актуализация опорных знаний и экспресс-разминка 8 минут 5 минут Первичный ключ vs Внешний ключ, ссылочная целостность, поиск O(N) vs O(log N)
3. Инструктаж и теоретический базис физического индексирования 18 минут 12 минут Структура B-Tree, Composite Index, кластеризация, Partial Index, накладные расходы
4. Разбор сквозного эталона и планов запросов EXPLAIN 12 минут 10 минут Seq Scan vs Index Scan, чтение EXPLAIN ANALYZE, блокировки при FK без индексов
5. Практическая работа студентов в zanyatie.html 28 минут 24 минуты Индивидуальное решение 4 дифференцированных кейсов (Банкинг, Связь, Недвижимость, Доставка)
6. Подведение итогов, рефлексия, закрытие критериев 9 минут 6 минут Разбор типичных ошибок, мем Little Bobby Tables (xkcd #327), фиксация оценок

2. Теоретико-методический базис физического индексирования

2.1. Структура сбалансированного дерева B-Tree

В большинстве современных реляционных СУБД (PostgreSQL, MySQL/InnoDB, Oracle, MS SQL Server) стандартным типом индекса по умолчанию является B-Tree (сбалансированное дерево поиска). Преподавателю важно подчеркнуть его физические свойства:

2.2. Уникальные vs Неуникальные индексы

Индекс выполняет две фундаментальные роли: ускорение поиска и принудительное обеспечение бизнес-ограничений целостности данных.

2.3. Составные индексы (Composite Index) и правило левого префикса

Составной индекс строится по нескольким столбцам: CREATE INDEX idx_abc ON T (A, B, C);. Данные в B-Tree сортируются строго лексикографически: сначала по колонке A, внутри одинаковых A — по B, внутри одинаковых B — по C.

Правило левого префикса (Left-Prefix Rule):
Индекс может использоваться СУБД только в том случае, если в условиях запроса (WHERE) присутствуют столбцы, начиная с самого левого (ведущего) столбца индекса без пропусков:
  • WHERE A = 1 AND B = 2 AND C = 3 — индекс используется полностью (все 3 поля).
  • WHERE A = 1 AND B = 2 — индекс используется эффективно по префиксу (A, B).
  • WHERE A = 1 — индекс используется эффективно по префиксу (A).
  • WHERE B = 2 AND C = 3 — индекс НЕ может использоваться для прямого поиска по дереву (нет ведущего поля A), СУБД выберет Seq Scan или Index Full Scan.
Золотое правило порядка полей в составном индексе:
[Столбцы точного равенства (=)] → [Столбцы диапазонных условий (<, >, BETWEEN)] → [Столбцы сортировки (ORDER BY)].
Если диапазонный столбец поставить первым, обход дерева по последующим столбцам точного равенства прекращается, превращая их в обычный фильтр (Filter Rows Removed).

2.4. Кластеризованные vs Некластеризованные индексы

Преподавателю необходимо разъяснить различие в архитектурах хранения данных различных СУБД:

2.5. Влияние индексов на скорость чтения vs Накладные расходы (Read vs Write Trade-off)

Главный парадокс индексирования:
Индексы ускоряют чтение (SELECT), но замедляют любую запись (INSERT, UPDATE, DELETE):
  • INSERT: Каждая вставка новой строки требует добавления записей во ВСЕ существующие индексы таблицы. Если страница индекса переполнена, происходит операция расщепления страницы (Page Split), вызывающая дорогой случайный ввод-вывод (Random I/O) и блокировку соседних узлов.
  • UPDATE: При изменении проиндексированного поля старая запись в индексе помечается удаленной, а новая вставляется в другую позицию B-Tree.
  • DELETE: Требует удаления ключа из всех индексных структур.
  • Расход дискового пространства и RAM: В высоконагруженных базах объем индексов нередко превышает объем самих таблиц в 2–3 раза, вытесняя горячие страницы данных из кэша Buffer Pool.

2.6. Внешние ключи (Foreign Keys) и критическая необходимость их индексации

Один из самых распространенных пробелов в подготовке выпускников СПО — убеждение, что СУБД автоматически создает индекс на внешний ключ. Это опасное заблуждение!

2.7. Чтение планов выполнения запросов EXPLAIN (Seq Scan vs Index Scan)

Оптимизатор запросов СУБД выбирает план выполнения на основе внутренней статистики распределения данных:

-- Пример плана без индекса:
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42;
-> Seq Scan on orders (cost=0.00..45210.00 rows=15 width=72) (actual time=0.045..142.310 rows=15 loops=1)
   Filter: (customer_id = 42)
   Rows Removed by Filter: 1999985

-- Пример плана с B-Tree индексом:
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42;
-> Index Scan using idx_orders_customer on orders (cost=0.43..12.50 rows=15 width=72) (actual time=0.021..0.052 rows=15 loops=1)
   Index Cond: (customer_id = 42)

3. Типовые ошибки студентов и педагогические приемы

Ошибка 1: «Индексы нужны на все столбцы таблицы»
Проявление: Студент создает 10 отдельных индексов на каждое поле таблицы.
Педагогический прием: Показать расчет накладных расходов. При 10 индексах одна операция INSERT превращается в 11 физических записей на диск. Спросить: «Что произойдет с биллинговой системой сотовых звонков при 5000 звонков в секунду? Сервер захлебнется в операциях I/O».
Ошибка 2: Нарушение порядка колонок в составном индексе
Проявление: Студент создает индекс (дата, id_клиента) под запрос WHERE id_клиента = 10 AND дата BETWEEN '...' AND '...'.
Педагогический прием: Метод телефонного справочника. Спросить студента: «Как быстрее найти человека: если справочник отсортирован сначала по дате рождения, а внутри по фамилии, или сначала по фамилии, а внутри по дате рождения?» Наглядная аналогия мгновенно закрепляет понимание селективности.
Ошибка 3: Создание B-Tree индекса на булево поле с низкой селективностью
Проявление: Индекс CREATE INDEX idx_status ON Users (is_active); при 98% активных пользователей.
Педагогический прием: Объяснить, что оптимизатор запросов просто проигнорирует такой индекс и выберет Seq Scan, так как случайное чтение по индексу половины таблицы медленнее, чем чтение всей таблицы подряд. Познакомить студентов с концепцией частичного индекса (Partial Index): WHERE is_active = false.
Ошибка 4: Игнорирование индексации внешних ключей
Проявление: Студент объявляет FOREIGN KEY, но забывает создать CREATE INDEX на эту колонку.
Педагогический прием: Продемонстрировать на проекторе блокировку таблицы Orders при попытке обновить строку в родительской таблице Customers.