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

Тема 3. Этапы проектирования баз данных — Практическое занятие №7: сортировка и фильтрация (Занятие №19)

1. Дидактический регламент и детальный тайминг занятия

Дисциплина «ОП.08 Основы проектирования баз данных». Практическое занятие рассчитано на 2 академических часа. Ниже представлены два взаимосогласованных сценария реализации: основной регламент (80 минут) и сокращенный регламент (60 минут).

Этап занятия Основной регламент (80 мин) Сокращенный регламент (60 мин) Дидактический фокус и действия преподавателя
1. Организационный момент и постановка инженерной проблемы 6 минут 4 минуты Приветствие, проверка готовности ПК и СУБД. Мотивационный кейс: падение производительности веб-приложения при выборке 20-й страницы каталога (деградация OFFSET 100000 и сброс сортировки на диск).
2. Актуализация опорных знаний и алгоритмический базис 14 минут 10 минут Фронтальный блиц-опрос. Разбор физики сортировки: внешняя сортировка слиянием (External Merge Sort), параметр work_mem, фаза генерации серий (runs) и n-путевое слияние (Merge Passes). Сравнение in-memory Quicksort и disk External Sort.
3. Инструктаж по многоуровневой сортировке, NULL и Collation 16 минут 12 минут Демонстрация презентации. Разбор синтаксиса: многоуровневый ORDER BY col1 ASC, col2 DESC, поведение NULLS FIRST / NULLS LAST в SQL стандартах и диалектах. Правила сравнения строк и локали (Collation, ICU vs libc, буква «Ё»).
4. Самостоятельная практическая работа в интерактивном листе 32 минуты 26 минут Студенты выполняют 4 дифференцированных практических кейса в zanyatie.html (Каталог товаров, Авиарейсы, Реестр договоров, Электронный журнал). Преподаватель проводит индивидуальные консультации и аудит SQL-запросов.
5. Экспертный разбор типичных ошибок, рефлексия и критериальное оценивание 12 минут 8 минут Разбор ключевых граблей (опасность OFFSET при пагинации, неустойчивая сортировка без первичного ключа, скрытый disk spill). Оценивание по рубрике (4-балльная шкала). Инструктаж по сохранению работы в PDF и резервному ДЗ.
Особенности сокращенного регламента (60 минут): Этап глубокого детального расчета дисковых проходов алгоритма External Merge Sort с ручным рисованием графа слияния переносится на домашнее изучение по конспекту (lekciya.html), а в классе разбирается базовый принцип work_mem и вывод плана EXPLAIN ANALYZE (Sort Method: external merge Disk).

2. Теоретико-методический фундамент сортировки и фильтрации

2.1. Многоуровневая сортировка кортежей (Multi-Column ORDER BY)

В реляционной теории отношения представляют собой неупорядоченные множества кортежей. Порядок строк на физическом диске не гарантирован. Единственным легитимным способом гарантировать порядок результирующего набора является явное указание предложения ORDER BY.

Многоуровневая сортировка выполняется слева направо по принципу лексикографической иерархии:

SELECT product_id, category_id, rating, price 
FROM products 
WHERE is_available = TRUE 
ORDER BY category_id ASC, rating DESC, price ASC;

СУБД сначала группирует строки по первому критерию (category_id). Если значения первого критерия совпадают (коллизия), сравнение переходит ко второму полю (rating). Если совпадают и они — к третьему полю (price). Если после всех критериев остаются дубликаты, а первичный ключ не включен в ORDER BY, результирующий порядок строк является неустойчивым (non-deterministic).

2.2. Трехзначная логика и поведение NULL-значений (NULLS FIRST / NULLS LAST)

В реляционной модели значение NULL обозначает отсутствие данных или неизвестность (unknown). Значение NULL не равно ничему, включая другой NULL (NULL = NULL возвращает UNKNOWN). Однако при сортировке СУБД обязана позиционировать кортежи с NULL.

2.3. Локали и правила сравнения символов (Collation)

Сортировка текстовых полей напрямую зависит от установленного правила сопоставления символов (Collation). Collation определяет таблицу весов символов, регистрозависимость (case sensitivity) и акцентозависимость (accent sensitivity).

2.4. Физический алгоритм сортировки: External Merge Sort и work_mem

Когда СУБД получает команду на сортировку массива кортежей, планировщик оценивает объем данных и доступную оперативную память, выделяемую процессу (параметр work_mem в PostgreSQL или sort_buffer_size в MySQL).

  1. In-Memory Sort (Quicksort / Top-N Heapsort): Если весь набор данных (или только ключи с указателями на строки — tuple pointers) умещается в work_mem, СУБД применяет быструю сортировку в ОЗУ. При наличии LIMIT k применяется алгоритм Top-N Heapsort с кучей размера $k$, что дает сложность $O(N \log k)$ без сортировки всей таблицы.
  2. External Merge Sort (Внешняя сортировка слиянием): Если объем данных превышает work_mem:
    • Фаза 1 (Run Generation): Данные порциями считываются в память, сортируются в пределах work_mem и сбрасываются во временные файлы на диск в виде отсортированных серий (Runs).
    • Фаза 2 (Merge Passes): СУБД выполняет многопутевое слияние (Multi-way Merge) отсортированных серий с диска с использованием очереди с приоритетом (K-way Tournament Tree / Min-Heap). Если число серий велико, слияние происходит в несколько проходов.
    • План EXPLAIN: Sort Method: external merge Disk: 14256kB. Сброс на диск резко увеличивает задержку (I/O latency) в сотни раз!

2.5. Пагинация данных: LIMIT / OFFSET vs Keyset Pagination

Реализация постраничного вывода (Pagination) — классическая задача веб-разработки и проектирования БД.

2.6. Индексная поддержка предикатной фильтрации и сортировки

Оптимальное выполнение запроса с фильтрацией и сортировкой достигается созданием составного B-Tree индекса, поддерживающего правило «Равенство → Сортировка → Диапазон» (Equality, Sort, Range — ESR):

-- Запрос:
SELECT * FROM orders 
WHERE client_id = 42 AND status = 'COMPLETED' 
ORDER BY order_date DESC 
LIMIT 10;

-- Идеальный составной индекс:
CREATE INDEX idx_orders_client_status_date 
ON orders (client_id, status, order_date DESC);

Благодаря такому индексу СУБД использует узел Index Scan, двигаясь по дереву в уже отсортированном порядке без дополнительной операции в памяти Sort (zero-cost ordering).

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

Педагогический прием «Предсказание плана выполнения до запуска»

Преподаватель проецирует на экран SQL-запрос с фильтрацией и ORDER BY по двум таблицам и просит студентов предсказать:

  1. Будет ли выполнен Index Scan или Seq Scan + Sort?
  2. Где окажутся значения NULL: вверху или внизу списка?
  3. Какой метод сортировки покажет EXPLAIN ANALYZE при work_mem = '4MB' на таблице в 1 000 000 записей?

Фиксация гипотез перед демонстрацией консоли включает когнитивное внимание и предотвращает пассивное запоминание.

Классификатор типовых студенческих ошибок

Ошибка 1: Иллюзия естественного порядка (Heavily Implicit Order)

Суть: Студент считает, что если строки вставлялись по порядку (auto-increment id), они всегда вернутся отсортированными без ORDER BY.
Контрпример: Достаточно выполнить операцию VACUUM, параллельное сканирование (Parallel Seq Scan) или обновить несколько строк (UPDATE), чтобы СУБД вернула строки в абсолютно произвольном порядке физических страниц кучи.

Ошибка 2: Недетерминированная пагинация (Non-deterministic Paging)

Суть: Сортировка по нетерминальному полю без уникального суффикса: ORDER BY date DESC LIMIT 10 OFFSET 10. Если 20 строк имеют одинаковую дату, при переходе со страницы 1 на страницу 2 СУБД может произвольно перетасовать эквивалентные строки, и клиент потеряет часть данных либо увидит дубли.
Решение: Всегда добавлять первичный ключ последним критерием (tie-breaker): ORDER BY date DESC, id DESC.

Ошибка 3: Ловушка неявного приведения типов и функций в WHERE (SARGability)

Суть: Оборачивание поля в функцию: WHERE EXTRACT(YEAR FROM created_at) = 2026 или WHERE lower(status) = 'active'. СУБД отключает B-Tree индекс и делает полный Seq Scan.
Решение: Использовать диапазонные предикаты: WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01' или создавать функциональный индекс (Expression Index).

Ошибка 4: Забытое позиционирование NULL в сортировке по убыванию

Суть: При сортировке товаров по рейтингу ORDER BY rating DESC в PostgreSQL товары с NULL (без отзывов) окажутся на самых первых строчках витрины магазина.
Решение: Явное указание ORDER BY rating DESC NULLS LAST.