Тема 3. Этапы проектирования баз данных — Практическое занятие №7: сортировка и фильтрация (Занятие №19)
Дисциплина «ОП.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 и резервному ДЗ. |
lekciya.html), а в классе разбирается базовый принцип work_mem и вывод плана EXPLAIN ANALYZE (Sort Method: external merge Disk).
В реляционной теории отношения представляют собой неупорядоченные множества кортежей. Порядок строк на физическом диске не гарантирован. Единственным легитимным способом гарантировать порядок результирующего набора является явное указание предложения 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).
В реляционной модели значение NULL обозначает отсутствие данных или неизвестность (unknown). Значение NULL не равно ничему, включая другой NULL (NULL = NULL возвращает UNKNOWN). Однако при сортировке СУБД обязана позиционировать кортежи с NULL.
NULL либо самым большим значением (больше любого существующего), либо самым маленьким, но обязана вести себя консистентно.NULL считается «наибольшим» значением. Поэтому при ASC значения NULL выводятся в конце (NULLS LAST), а при DESC — в самом начале (NULLS FIRST).NULL считается «наименьшим» значением (при ASC — в начале, при DESC — в конце).ORDER BY rating DESC NULLS LAST или ORDER BY flight_gate ASC NULLS FIRST.Сортировка текстовых полей напрямую зависит от установленного правила сопоставления символов (Collation). Collation определяет таблицу весов символов, регистрозависимость (case sensitivity) и акцентозависимость (accent sensitivity).
"C" / POSIX: Сортировка по бинарным кодам байтов UTF-8 / ASCII. Заглавные латинские буквы идут раньше строчных, а русские буквы сортируются по кодам таблицы. Буква «Ё» (код U+0401) окажется в начале алфавита, перед «А»!"ru_RU.UTF-8" / ICU: Алфавитная сортировка с учетом правил русского языка, где буква «е» и «ё» упорядочиваются корректно, а регистр игнорируется на первичном уровне сравнения (case-insensitive tie-breaking).ORDER BY last_name COLLATE "ru_RU" ASC.Когда СУБД получает команду на сортировку массива кортежей, планировщик оценивает объем данных и доступную оперативную память, выделяемую процессу (параметр work_mem в PostgreSQL или sort_buffer_size в MySQL).
work_mem, СУБД применяет быструю сортировку в ОЗУ. При наличии LIMIT k применяется алгоритм Top-N Heapsort с кучей размера $k$, что дает сложность $O(N \log k)$ без сортировки всей таблицы.work_mem:
work_mem и сбрасываются во временные файлы на диск в виде отсортированных серий (Runs).Sort Method: external merge Disk: 14256kB. Сброс на диск резко увеличивает задержку (I/O latency) в сотни раз!Реализация постраничного вывода (Pagination) — классическая задача веб-разработки и проектирования БД.
SELECT * FROM items ORDER BY id LIMIT 20 OFFSET 100000;SELECT * FROM items WHERE (created_at, id) < ($last_created, $last_id) ORDER BY created_at DESC, id DESC LIMIT 20;Оптимальное выполнение запроса с фильтрацией и сортировкой достигается созданием составного 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).
Преподаватель проецирует на экран SQL-запрос с фильтрацией и ORDER BY по двум таблицам и просит студентов предсказать:
Index Scan или Seq Scan + Sort?NULL: вверху или внизу списка?EXPLAIN ANALYZE при work_mem = '4MB' на таблице в 1 000 000 записей?Фиксация гипотез перед демонстрацией консоли включает когнитивное внимание и предотвращает пассивное запоминание.
Суть: Студент считает, что если строки вставлялись по порядку (auto-increment id), они всегда вернутся отсортированными без ORDER BY.
Контрпример: Достаточно выполнить операцию VACUUM, параллельное сканирование (Parallel Seq Scan) или обновить несколько строк (UPDATE), чтобы СУБД вернула строки в абсолютно произвольном порядке физических страниц кучи.
Суть: Сортировка по нетерминальному полю без уникального суффикса: ORDER BY date DESC LIMIT 10 OFFSET 10. Если 20 строк имеют одинаковую дату, при переходе со страницы 1 на страницу 2 СУБД может произвольно перетасовать эквивалентные строки, и клиент потеряет часть данных либо увидит дубли.
Решение: Всегда добавлять первичный ключ последним критерием (tie-breaker): ORDER BY date DESC, id DESC.
Суть: Оборачивание поля в функцию: 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).
Суть: При сортировке товаров по рейтингу ORDER BY rating DESC в PostgreSQL товары с NULL (без отзывов) окажутся на самых первых строчках витрины магазина.
Решение: Явное указание ORDER BY rating DESC NULLS LAST.