Развернутый сценарий проведения учебного занятия (Конспект)

Тема 3. Этапы проектирования баз данных — Практическое занятие №6: ключевые поля, индексы, связи (Занятие №18)
Дисциплина: ОП.08 Основы проектирования баз данных
Специальность: 09.02.06 Сетевое и системное администрирование
Регламенты: Основной 80 минут / Сокращенный 60 минут
Учебная группа: СИЭУиП, 2 курс

Этап 1. Организационный момент и проблемная мотивация 80 мин: 5 мин | 60 мин: 3 мин

Преподаватель приветствует обучающихся, отмечает присутствующих в журнале, проверяет готовность интерактивных терминалов и проектора.
Прямая речь преподавателя:
«Здравствуйте, коллеги! Прошу садиться. Сегодня мы проводим Практическое занятие №6, посвященное ключевым полям, физическим индексам и связям в реляционных базах данных.

Представьте реальную производственную ситуацию из практики финансового сектора. Успешный интернет-банк выпустил масштабное обновление мобильного приложения. Первого числа месяца ровно в 9:00 утра 50 000 клиентов одновременно открыли приложение, чтобы получить выписку по операциям за прошлый месяц. Через две минуты сервер базы данных ушел в глухой отказ: загрузка дисковой подсистемы достигла 100%, процессорные ядра захлебнулись в операциях ожидания I/O, время отклика выросло с 20 миллисекунд до бесконечности. Платежи встали, клиенты в ярости.

Дежурный архитектор баз данных подключился к серверу, выполнил ровно одну команду DDL, добавив один правильный индекс, и спустя 10 секунд нагрузка упала до 2%, а выписки стали формироваться мгновенно за 2 миллисекунды. Сегодня на практическом занятии каждый из вас разберется, как именно устроена физика такого ускорения, почему неправильно спроектированные связи могут парализовать работу сервера, и как проектировать индексы под высоконагруженные запросы».
Ожидаемая реакция обучающихся:
Студенты включаются в обсуждение, выдвигают предположения: сервер не успевал читать всю таблицу транзакций; выполнялся последовательный перебор строк; таблица была заблокирована.

Этап 2. Актуализация опорных знаний 80 мин: 8 мин | 60 мин: 5 мин

Фронтальный блиц-опрос по ранее пройденному материалу: реляционные таблицы, первичные и внешние ключи, физическое хранение строк в куче (Heap).
Прямая речь преподавателя:
«Прежде чем перейти к проектированию, давайте вспомним основы. На прошлых занятиях мы говорили о концептуальном и логическом проектировании, привели таблицы к третьей нормальной форме. Таблицы идеальны с точки зрения математики. Но как строки таблицы хранятся физически на диске?

Михаил, напомните, в каком порядке располагаются строки таблицы в файле данных на жестком диске или SSD?»
Ответ студента (Михаил):
«Строки хранятся без строгого порядка в неупорядоченном пространстве — в куче (Heap). Новые записи попадают на свободные места страниц, куда укажет СУБД».
Прямая речь преподавателя:
«Абсолютно верно! А теперь главный вопрос: если в таблице 10 миллионов строк, и мы ищем запись по условию WHERE номер_телефона = '+79123456789', что вынуждена сделать СУБД, если индекса нет?»
Ответ студента (Анастасия):
«СУБД придется выполнить последовательное сканирование — Seq Scan. То есть прочитать с диска все страницы таблицы до единой и проверить каждую строчку. Это алгоритмическая сложность O(N)».
Прямая речь преподавателя:
«В точку! Чтение гигабайтов данных с диска ради поиска одной-единственной строки. И самый коварный вопрос, на котором сыплются 90% начинающих инженеров: когда мы создаем связь через FOREIGN KEY, создает ли СУБД индекс на внешний ключ автоматически?»
Ответ студента (Дмитрий):
«Кажется, да, ведь мы объявили ограничение целостности?»
Прямая речь преподавателя:
«А вот и нет! Это самое распространенное и фатальное заблуждение. СУБД автоматически создает индекс только на первичный ключ (PRIMARY KEY). Внешний ключ по умолчанию остается "голым". И к каким катастрофам это приводит, мы сейчас детально разберем».

Этап 3. Инструктаж и теоретический базис физического индексирования 80 мин: 18 мин | 60 мин: 12 мин

Демонстрация слайдов интерактивной презентации (слайды 3–12). Разбор архитектуры сбалансированного дерева B-Tree, составных индексов, правила левого префикса и компромисса чтения/записи.
Прямая речь преподавателя:
«Обратите внимание на слайд 4. Перед вами архитектура сбалансированного дерева поиска — B-Tree. Это рабочий инструмент по умолчанию в PostgreSQL, MySQL, Oracle и MS SQL Server.

Почему B-Tree столь эффективно? Во-первых, оно строго сбалансировано: глубина всех листовых узлов одинакова. Во-вторых, его коэффициент ветвления (Fan-out) огромен: в одну страницу 8 КБ помещается до 500 ключей с указателями. Поэтому дерево глубиной всего в 3–4 уровня покрывает таблицы на сотни миллионов записей!

Посмотрите, как происходит поиск ключа 25 (слайд 5). СУБД читает корень: 25 меньше 50 — шаг влево. Читает промежуточный узел: 25 между 20 и 35 — шаг в средний лист. Читает листовой узел: находит ключ 25 и считывает физический указатель TID (блок 7, позиция 3). И сразу делает ровно один точечный запрос к таблице. Итого: вместо 500 000 операций чтения СУБД делает 4 операции ввода-вывода за доли миллисекунды!

Теперь перейдем к составным индексам (слайд 7). Запомните фундаментальное правило: правило левого префикса. Индекс (A, B, C) отсортирован лексикографически: сначала по A, затем по B, затем по C. Если в вашем запросе нет колонки A, индекс по B-Tree работать не будет! СУБД не сможет зайти в нужную ветвь дерева.

И запомните золотую формулу порядка столбцов в составном индексе:
[Столбцы точного равенства =] → [Столбцы диапазона <, >, BETWEEN] → [Столбцы сортировки ORDER BY].
Если вы поставите диапазонное поле первым, обход дерева по остальным полям прекратится!

А теперь о цене (слайд 10). Индексы — это не бесплатный сыр. Запомните: индексы ускоряют чтение, но замедляют любую запись (INSERT, UPDATE, DELETE). Каждая новая строчка требует синхронной вставки во все деревья индексов. Если лист переполнен, происходит расщепление узла (Page Split) — дорогой дисковый ввод-вывод. Если на таблице 10 индексов, то один INSERT порождает 11 записей на диск. База данных просто захлебнется».

Этап 4. Разбор сквозного инженерного кейса и планов EXPLAIN 80 мин: 12 мин | 60 мин: 10 мин

Преподаватель открывает терминал СУБД и демонстрирует реальный план выполнения запроса до и после создания составного индекса.
Прямая речь преподавателя:
«Взгляните на экран проектора. Мы выполняем поиск заказов клиента:
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 502 AND status = 'NEW';
И что мы видим в выводе?
Seq Scan on orders (cost=0.00..45210.00 rows=12 width=80)
Filter: ((customer_id = 502) AND (status = 'NEW'))
Rows Removed by Filter: 1999988
Смотрите на цифру Rows Removed by Filter: 1999988! База данных честно прочитала 2 миллиона записей с накопителя, выбросила почти все в корзину и вернула всего 12 строк. Стоимость (cost) — 45 210 условных единиц.

Теперь создаем правильный составной индекс:
CREATE INDEX idx_orders_customer_status ON orders (customer_id, status);
Повторяем тот же самый EXPLAIN ANALYZE:
Index Scan using idx_orders_customer_status on orders (cost=0.43..8.50 rows=12 width=80)
Index Cond: ((customer_id = 502) AND (status = 'NEW'))
Стоимость упала с 45 210 до 8.5! Читаются только 12 листовых записей, время отклика — 0.04 миллисекунды.

И вторая демонстрация: таблица order_items, ссылающаяся на orders. Внешний ключ не проиндексирован. Администратор удаляет старый тестовый заказ: DELETE FROM orders WHERE id = 1;. Что делает СУБД? Чтобы убедиться, что в order_items нет позиций этого заказа, она накладывает эксклюзивную блокировку на ВСЮ таблицу order_items и запускает Seq Scan. В этот момент весь интернет-магазин перестает оформлять заказы. Добавляем CREATE INDEX ON order_items (order_id); — и проверка ссылочной целостности происходит за одну операцию поиска по индексу без блокировки таблицы».

Этап 5. Практическая работа студентов в zanyatie.html 80 мин: 28 мин | 60 мин: 24 мин

Студенты запускают интерактивный рабочий лист zanyatie.html, заполняют учетные данные и приступают к проектированию одного из 4 вариантов.
Прямая речь преподавателя:
«Коллеги, открываем рабочий лист zanyatie.html. Введите вашу фамилию, имя и номер учебной группы. Ваши ответы сохраняются локально в браузере.

Перед вами 4 дифференцированных практических кейса:
  • Вариант 1 (Интернет-банкинг): проектирование связей таблиц Счета и Транзакции, обязательная индексация FK счета, синтез составного индекса выписки (id_клиента, дата_транзакции), расчет ускорения.
  • Вариант 2 (Биллинг связи): абоненты, звонки и тарифы. Проектирование частичного индекса (Partial Index) на активные вызовы WHERE статус = 'ACTIVE', обоснование экономии RAM.
  • Вариант 3 (Каталог недвижимости): объекты, риелторы, города. Составной индекс по диапазону (город_id, комнат, цена), строгое обоснование расположения диапазонного столбца цены последним.
  • Вариант 4 (Логистика и доставка): заказы, курьеры, маршруты. Создание уникального индекса на трек-номер, индексация FK курьера для оперативных отчетов.
В каждом варианте вам необходимо написать DDL-скрипты связей и индексов, обосновать селективность, доказать соблюдение правила левого префикса, оценить накладные расходы DML и ответить на контрольные вопросы самопроверки. Приступаем к работе, при возникновении вопросов поднимайте руку».
Преподаватель осуществляет индивидуальный обход аудитории, контролирует ход проектирования, указывает студентам на ошибки в расположении диапазонных колонок и пропуски индексов на внешних ключах.

Этап 6. Подведение итогов, рефлексия и оценка 80 мин: 9 мин | 60 мин: 6 мин

Подведение итогов практического занятия, экспертный разбор типовых ошибок, демонстрация завершающего слайда 15 с веб-комиксом xkcd #327.
Прямая речь преподавателя:
«Завершаем заполнение рабочих листов. Давайте подведем итоги.

Сегодня мы увидели, что реляционная база данных живет по строгим законам физики накопителей. Нормализовать схему до 3НФ — это лишь половина дела. Если вы не спроектировали физические индексы под профиль запросов, система рухнет при первой же нагрузке.

Какие три главных вывода вы должны забрать с сегодняшней пары?
  1. Внешние ключи ОБЯЗАНЫ быть проиндексированы вручную. Иначе вас ждут медленные JOIN и каскадные блокировки целых таблиц при DELETE.
  2. Правило левого префикса незыблемо. Диапазоны ставим строго после равенств: (id_клиента, дата), а не наоборот.
  3. Индексы не бесплатны. Каждый индекс бьет по скорости INSERT и раздувает объем дискового пространства. Не плодите мусорные индексы на булевы поля.
А чтобы вы всегда помнили о важности строгости при работе со схемами, ключами и валидацией данных — посмотрите на экран (слайд 15 презентации). Это легендарный комикс xkcd про "Little Bobby Tables" — школьника Роберта, чье имя содержало SQL-инъекцию, стершую всю таблицу студентов.

Ваши работы в zanyatie.html будут проверены по 4-балльной критериальной шкале: 2 балла за проектирование ключей и индексов, 1 балл за обоснование селективности и префикса, 1 балл за оценку накладных расходов и самопроверку. Нажмите кнопку "Экспорт в PDF" для сохранения локальной копии протокола. Для тех, кому необходимо закрыть пропуски или отработать пару дистанционно, доступно резервное домашнее задание domashnee_zadanie.html. Спасибо за активную инженерную работу, занятие окончено!»