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

Дисциплина: ОП.08 Основы проектирования баз данных | Тема 3. Этапы проектирования баз данных (§2.2 с.7 программы)

Практическое занятие №8: поиск по одному и нескольким полям (Занятие 20, финал семестра 3, 2 академических часа)

1. Детальный тайминг занятия (основной 80 минут и сокращенный 60 минут)

Занятие 20 завершает учебную программу 3-го семестра. Главная цель — закрепить умение проектировать эффективные поисковые запросы по одному и нескольким полям, сопоставлять физические механизмы поиска СУБД с предикатами запроса и составлять строгий поисковый протокол с анализом времени отклика и планов выполнения.

Этап занятия Основной регламент (80 мин) Сокращенный регламент (60 мин) Педагогическая задача и содержание этапа
1. Организационный момент и мотивация 5 минут 3 минуты Приветствие, проверка явки, фиксация статуса завершения 3-го семестра. Озвучивание проблемы: «Почему при миллионе записей сайт падает на обычном поиске по каталогу?».
2. Актуализация опорных знаний 10 минут 7 минут Фронтальный опрос: понятие индекса B-Tree, физический доступ через кучу (Heap), логарифмическая сложность $O(\log N)$ против линейной $O(N)$ при полном сканировании (Sequential Scan).
3. Инструктаж и методический разбор механизмов поиска 15 минут 10 минут Демонстрация преподавателем 4 физических механизмов: точечный поиск по первичному/уникальному ключу, диапазонный поиск (Index Range Scan), сопоставление с шаблоном (LIKE), полнотекстовый поиск (FTS, GIN).
4. Самостоятельная практическая работа студентов 40 минут 32 минуты Студенты работают в интерактивном листе zanyatie.html по 4 вариантам. Составление SQL-запросов, фиксация времени отклика, структуры индексов и заполнение поискового протокола.
5. Защита протоколов, подведение итогов семестра 3 и рефлексия 10 минут 8 минут Критериальный разбор типовых ошибок, выставление баллов в ведомость (шкала 0–4 балла), фиксация итогов освоения Темы 3 и завершения 3 семестра.

2. Архитектура поисковых механизмов реляционных СУБД

2.1. Точечный поиск по ключу: Index Scan и сложность $O(\log N)$

Точечный поиск по равенству (WHERE primary_key = constant) опирается на классическую древовидную структуру B-Tree (Balanced Tree). В таблице без индекса поиск требует Sequential Scan — чтения всех $M$ дисковых страниц (блоков по 8 КБ в PostgreSQL), что приводит к вычислительной сложности $O(N)$ и катастрофической деградации дискового ввода-вывода (I/O Bottleneck).

Формула логарифмической глубины B-Tree:

Высота сбалансированного дерева $H$ определяется коэффициентом ветвления (Fan-out) $B \approx 200..500$:

H \le \lceil \log_B (N) \rceil + 1

Для таблицы из 20 000 000 записей глубина дерева составляет всего 3–4 уровня. Точечный поиск считывает ровно 3 страницы индекса и 1 страницу кучи таблицы (Heap Page). Время выполнения: < 0.05 миллисекунды.

2.2. Диапазонный поиск: Index Range Scan и горизонтальные связи листьев

Диапазонные предикаты (WHERE column BETWEEN A AND B, >=, <=) эксплуатируют фундаментальное свойство B-Tree: все листовые узлы связаны между собой двусвязным списком в строго отсортированном порядке.

2.3. Сопоставление с шаблоном: оператор LIKE и правило левого префикса

Один из самых коварных разделов проектирования запросов — поиск по строковым маскам:

Поиск по левому префиксу: LIKE 'text%'

СУБД транслирует предикат в диапазон: col >= 'text' AND col < 'texu'. Используется Index Range Scan. Поиск выполняется мгновенно за логарифмическое время.

Важно для PostgreSQL: В локалях non-C индекс B-Tree должен быть создан с операторным классом varchar_pattern_ops!

Поиск с ведущим подстановочным знаком: LIKE '%text%'

B-Tree индекс БЕСПОЛЕЗЕН! Так как первый символ строки неизвестен, маршрутизация по дереву невозможна. СУБД вынуждена запускать полный Seq Scan, считывая терабайты диска.

Инженерное решение: Использование расширения pg_trgm с триграммными индексами GIN или перенос задачи в полнотекстовый поиск.

2.4. Полнотекстовый поиск (FTS): стемминг, стоп-слова и инвертированный индекс GIN

Когда требуется искать слова и фразы в неструктурированных текстах (аннотации книг, описания товаров, история обращений), оператор LIKE терпит крах не только по скорости, но и по смыслу (он не учитывает окончания, падежи и предлоги).

Полнотекстовый поиск в PostgreSQL базируется на трех компонентах:

  1. Стемминг (Stemming): Морфологический редуктор (Snowball) отсекает окончания и суффиксы, приводя слова к единой нормальной лексеме (например, «базами», «баз», «базе» $\to$ лексема 'баз').
  2. Словари стоп-слов: Фильтрация частотного языкового шума (предлоги «и», «в», «на», союзы, местоимения), который не несет смысловой нагрузки при поиске.
  3. Типы данных tsvector и tsquery: Документ конвертируется в отсортированный список нормализованных лексем с их позициями (to_tsvector('russian', text)), а поисковый запрос — в булево выражение лексем (to_tsquery('russian', 'база & проект')). Сопоставление выполняется бинарным оператором @@.
  4. Инвертированный индекс GIN (Generalized Inverted Index): В B-Tree ключ — это целая колонка, указывающая на строку. В GIN ключами B-Tree являются отдельные лексемы (слова), а в листьях хранятся отсортированные списки идентификаторов всех строк (Posting Lists), содержащих это слово. Поиск любого сочетания слов выполняется за доли миллисекунды через пересечение битовых карт (Bitmap Index Scan).

3. Составление поискового протокола

Поисковый протокол — это профессиональный отчет инженера баз данных, фиксирующий поведение оптимизатора запросов при различных формах фильтрации. Протокол должен содержать:

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

Ошибка 1. «Вера во всемогущество B-Tree при LIKE '%текст%'»

Симптом: Студент строит обычный индекс CREATE INDEX ON users(name) и удивляется, почему запрос WHERE name LIKE '%иван%' выполняется 3 секунды и планировщик пишет Seq Scan.

Педагогический прием «Аналогия с телефонным справочником»: Преподаватель просит студента: «Найди мне в бумажном телефонном справочнике абонента, у которого фамилия оканчивается на "...ов". С какой страницы ты начнешь?». Студент осознает, что без знания первой буквы справочник придется перелистывать целиком от корки до корки.

Ошибка 2. Нарушение правила порядка полей в составном индексе

Симптом: Для запроса WHERE region = 'Югра' AND income > 100000 создается индекс (income, region).

Педагогический прием «Иерархия фильтрации»: Разбор на доске. Если первым идет диапазон income > 100000, то все строки с доходами выше 100 тысяч разбросаны по разным регионам. Ветвь region = 'Югра' внутри диапазона не сгруппирована. Правило: Равенство ВСЕГДА ставится левее диапазона!

Ошибка 3. Игнорирование стемминга в текстовом поиске

Симптом: Попытка реализовать поиск по каталогу книг через WHERE title LIKE '%база%', из-за чего книги с названием «Основы реляционных баз данных» не находятся.

Педагогический прием: Сравнение вывода to_tsvector('russian', 'Базами данных') и демонстрация лексемы 'баз':1. Объяснение, почему коммерческие поисковые интерфейсы строятся на FTS и инвертированных индексах.