Лекции · конспект 3 из 9

Ключи. Нормализация данных. Индексация данных

О чём эта тема
Три механизма, превращающие набор таблиц в надёжную базу данных: ключи, которые делают записи различимыми и связывают таблицы; нормализация, которая изгоняет избыточность и аномалии; индексы, которые превращают полное сканирование в мгновенный поиск.
Аннотация
Конспект последовательно разбирает семейство ключей реляционной модели: потенциальный, составной, первичный, суперключ, альтернативный и внешний — каждый с примером на таблицах студентов. Затем — нормализация: почему избыточность порождает аномалии вставки, обновления и удаления, и как последовательное приведение к первой, второй и третьей нормальным формам разбивает одну проблемную таблицу на согласованную схему из трёх; каждый шаг можно пройти в интерактивном стёппере. Третья часть посвящена индексации: как устроены B-дерево, bitmap-индекс, хэш-индекс и обобщённое поисковое дерево GiST, в чём их сильные и слабые стороны и когда каждый из них выбирать. Тренажёр «гонка индексов» наглядно сравнивает число сравнений при полном сканировании и при поиске по дереву. Завершают конспект пять реальных сценариев создания индексов — от интернет-магазина до ГИС.
Пререквизиты
Лекция 1 (отношение, атрибут, домен) и лекция 2 (потенциальный ключ, реляционная алгебра).
Мотивация
Представьте таблицу сотрудников, где отдел и руководитель записаны в каждой строке. Пока строк десять — всё работает. Но вот руководитель отдела сменился: нужно обновить сотню строк, и если хоть одна пропущена — база противоречит сама себе. А при удалении последнего сотрудника отдела из базы бесследно исчезает сам отдел. Это не гипотетика, а три классические аномалии, у которых есть систематическое лекарство — нормализация. Вторая половина мотивации — скорость: запрос по неиндексированному полю в таблице на миллион строк заставляет СУБД прочитать миллион строк. Индекс сокращает работу до пары десятков сравнений — и в этой лекции видно, почему.

1. Ключи и их виды

В реляционных базах данных ключи играют важную роль в обеспечении уникальности записей и поддержании целостности данных.

Определение

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

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

Ключи в схеме базы данных

1.1. Потенциальный ключ

Потенциальный ключ (ключ-кандидат) — это минимальный набор атрибутов, который может однозначно идентифицировать кортеж. Его свойства:

Например, в отношении STUDENT атрибут STUD_NO — ключ-кандидат: он уникально идентифицирует студентов.

STUD_NONAMECITYTELEPHONE
1ИванБиробиджан+7 (8212) 28-52-68
2МарьяСтерлитамак+7 (8212) 28-52-05
3НиколайБаклань+7 (8212) 28-51-30

Потенциальный ключ может быть простым (из одного атрибута) или составным. Составной ключ — комбинация нескольких полей, которая используется для уникальной идентификации записей. Например, в отношении STUDENT_COURSE составным ключом-кандидатом может служить комбинация {Year_in, Faculty, Spec, Group}:

STUD_NOYear_inFacultySpecGroup
12022ГФАКС
22024ФГиИБИС

1.2. Первичный ключ

Из множества потенциальных ключей отношения выбирается один, который становится первичным ключом (primary key). Например, STUD_NO в таблице STUDENT. Первичный ключ уникален и не может содержать NULL-значений; он может состоять из одного или нескольких столбцов.

1.3. Суперключ

Суперключ — набор атрибутов, который может однозначно идентифицировать кортеж. Например, STUD_NO и (STUD_NO, SNAME) — суперключи. Суперключ может включать NULL-значения; добавление любых атрибутов к ключу-кандидату формирует суперключ.

Суперключ отличается от потенциального ключа тем, что на него не накладывается требование минимальности (несократимости) — отсутствия меньшего подмножества атрибутов, удовлетворяющего условию уникальности. Вследствие этого в состав суперключа может входить другой, более «компактный» суперключ.

Соотношение видов ключей в СУБД
Типичная ошибка Путать суперключ с потенциальным ключом. Всякий потенциальный ключ — суперключ, но не наоборот: (STUD_NO, NAME) уникален, однако сократим — NAME можно убрать, и уникальность сохранится. Значит, это суперключ, но не потенциальный ключ.

1.4. Альтернативный ключ

Альтернативный ключ — это ключ-кандидат, который не был выбран в качестве первичного. Все ключи, не являющиеся первичными, называются альтернативными. Например, если первичным ключом таблицы STUDENT выбран STUD_NO, то другие потенциальные ключи (скажем, NAME или CITY, если их уникальность гарантирована предметной областью) становятся альтернативными.

1.5. Внешний ключ

Внешний ключ (foreign key) — атрибут, который может принимать только те значения, которые присутствуют в качестве значений другого атрибута. Отношение, на которое ссылаются, называется ссылочным отношением, а соответствующий атрибут — ссылочным атрибутом. Ссылочный атрибут должен быть первичным ключом в другом отношении.

STUD_NONAMECITYTELEPHONE
1ИванБиробиджан+7 (8212) 28-52-68
2МарьяСтерлитамак+7 (8212) 28-52-05
3НиколайБаклань+7 (8212) 28-51-30
STUD_NOYear_inFacultySpecGroup
12022ГФАКС
22024ФГиИБИС

Здесь атрибут STUD_NO таблицы STUDENT_COURSE — внешний ключ по отношению к атрибуту STUD_NO таблицы STUDENT.

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

Виды ключей реляционной таблицы

2. Нормализация данных

Нормализация базы данных — метод проектирования реляционных БД, который помогает правильно структурировать таблицы данных. Процесс направлен на создание системы с чётким представлением информации и взаимосвязей — без избыточности и потери данных.

Нормализация — итеративный процесс: она выполняется через серию тестов, и каждый последующий шаг разбивает таблицу на более лёгкую в управлении информацию, повышая общую логичность системы и простоту работы с ней.

Нормализация позволяет оптимально распределять атрибуты по таблицам и избавляет от:

Полную нормализацию выполнять не обязательно, однако она гарантирует полноценно функционирующую информационную среду. Метод:

2.1. Избыточность и аномалии

Когда в таблицу с избыточностью вносятся изменения, приходится корректировать все повторяющиеся экземпляры данных и связанные с ними объекты. Если этого не сделать, таблица становится несогласованной — возникают аномалии. Рассмотрим таблицу:

Employee_IDEmployee_NameSectorManager
1AdamFinanceAdam
2JacobFinanceAdam
3JoshuaFinanceAdam
4EmilyMarketingEmily

Для неё характерна избыточность данных, а при изменении данных возникают три аномалии.

1. Аномалия вставки. При добавлении нового сотрудника (employee) в отдел (sector) Finance обязательно указывается его руководитель (manager) — иначе данные вставить не удастся, даже если информация о руководителе отдела в базе уже есть:

Employee_IDEmployee_NameSectorManager
5New_EmployeeFinanceошибка — не указан менеджер

2. Аномалия обновления. Когда сотрудник переходит в другой отдел, поле «Руководитель» содержит ошибочные данные: Джейкоб (Jacob) перешёл в Marketing, но его руководителем по-прежнему показан Адам:

Employee_IDEmployee_NameSectorManager
2JacobMarketingAdam (ошибка)

3. Аномалия удаления. Если Джошуа (Joshua) уволится и его строка будет удалена, потеряется информация о том, что отдел Finance вообще существует — вместе с последним сотрудником исчезают сведения об отделе.

2.2. Основные понятия нормализации

Простейшие понятия, используемые в нормализации:

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

Иерархия нормальных форм

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

СтадияЧто устраняется
Ненормализованная форма (UNF)состояние до нормализации: избыточные и сложные значения
Первая нормальная форма (1НФ)повторяющиеся и сложные значения; все экземпляры становятся атомарными
Вторая нормальная форма (2НФ)частичные зависимости выносятся в новые таблицы; строки функционально зависят от первичного ключа
Третья нормальная форма (3НФ)транзитивные зависимости выносятся в новые таблицы; неключевые атрибуты зависят от первичного ключа
Нормальная форма Бойса — Кодда (НФБК)транзитивные и частичные зависимости для всех потенциальных ключей
Четвёртая нормальная форма (4НФ)многозначные зависимости
Пятая нормальная форма (5НФ)JOIN-зависимости (зависимости соединения)

База данных считается нормализованной после достижения третьей нормальной формы. Дальнейшие этапы усложняют структуру БД и могут нарушить функциональность системы.

2.3. Нормализация по шагам

Общие этапы нормализации подходят для всех таблиц; конкретные методы разделения зависят от предметной области. Разберём классический пример — таблицу сотрудников с руководителями и отделами. В ненормализованной таблице один столбец содержит несколько значений, а данные о руководителях дублируются:

Ненормализованная таблица

Шаг 1: первая нормальная форма (1НФ). Значения полей должны быть атомарными: все сложные сущности разделяются на новые строки или столбцы. Чтобы не потерять информацию, для каждого сотрудника дублируются значения столбцов managerID, managerName и area:

Таблица в первой нормальной форме

Шаг 2: вторая нормальная форма (2НФ). Каждая строка таблицы должна зависеть от первичного ключа целиком. Таблица разделяется на две: Manager (managerID, managerName, area) и Employee (employeeID, employeeName, managerID, sectorID, sectorName) — без частичных зависимостей:

Таблица Manager
Таблицы во второй нормальной форме

Шаг 3: третья нормальная форма (3НФ).

Определение

Транзитивная зависимость — функциональная зависимость между тремя атрибутами: второй атрибут зависит от первого, а третий — от второго. Благодаря транзитивности третий атрибут зависит от первого.

Третья нормальная форма разделяет любые транзитивные функциональные зависимости. В нашем примере транзитивная зависимость есть у таблицы Employee (employeeID → sectorID → sectorName); она разбивается на две новые таблицы — Employee (employeeID, employeeName, managerID, sectorID) и Sector (sectorID, sectorName):

Таблица Employee в третьей нормальной форме
Таблица Sector

Конечная структура — три взаимосвязанные таблицы:

Итоговая нормализованная структура

Теперь база данных считается нормализованной. Дальнейшая нормализация зависит от конкретных целей. Пройдите те же шаги в интерактивном стёппере: на каждом шаге красным подсвечена проблема, зелёным — что изменилось.

Тренажёр: нормализация по шагам

3. Индексация

Индексирование баз данных — техника, повышающая скорость и эффективность запросов. Она создаёт отдельную структуру данных, сопоставляющую значения в одном или нескольких столбцах таблицы с местоположениями строк на физическом накопителе, что позволяет базе быстро находить строки без сканирования всей таблицы. Индексы занимают место и должны обновляться при изменении данных, поэтому стратегию индексирования важно продумывать и регулярно оптимизировать.

Общие этапы создания индекса:

  1. определить столбцы для индексирования — обычно те, что чаще всего используются в запросах и поиске;
  2. выбрать алгоритм индексирования, подходящий типу данных: B-деревья — для строковых и числовых данных, полнотекстовые индексы — для текстов;
  3. применить алгоритм к выбранным столбцам — создаётся структура, сопоставляющая значения с местоположениями записей;
  4. сохранить индекс в отдельной структуре данных — в другой части диска или в памяти, где доступ к нему эффективнее, чем к самой таблице;
  5. обновлять индекс при добавлении, удалении и изменении записей.

Индекс существенно ускоряет запросы и поиск, но имеет цену: рост требований к объёму хранилища и замедление вставки и обновления. Перед созданием индекса следует взвесить плюсы и минусы.

3.1. B-дерево

B-tree (сбалансированное дерево) — самый распространённый тип индекса в PostgreSQL. Он поддерживает все стандартные операции сравнения (>, <, >=, <=, =, <>) и применим к большинству типов данных. B-tree индексы используются для сортировки, ограничений уникальности и поиска по диапазону значений.

Структура B-дерева

Главное преимущество B-дерева — минимизация дисковых операций ввода-вывода: все узлы-листья находятся на одном уровне, а каждый узел хранит множество ключей и указателей. Количество ключей в узле определяется параметром, называемым «порядком» дерева.

Недостатки B-деревьев:

3.2. Bitmap-индекс

Bitmap-индексирование использует битовые карты для обозначения наличия или отсутствия значения в таблице. Это успешная техника для таблиц с низкой кардинальностью, где количество уникальных значений в столбце мало по сравнению с общим числом строк.

Устройство bitmap-индекса

Битовые карты крайне компактны и быстро сканируются, поэтому bitmap-индексы удобны в хранилищах данных, где нужно быстро просматривать огромные объёмы, и в базах с большим количеством чтений при редких обновлениях.

Недостатки:

3.3. Хэш-индекс

Hash-индексы предназначены для быстрого доступа к данным по равенству. Они менее универсальны, чем B-tree, и не поддерживают сортировку или поиск по диапазону, из-за чего на практике используются редко.

Устройство хэш-индекса

Сопоставление ключей с местоположениями записей даёт поиск и вставку за постоянное время O(1). Однако метод плохо работает с запросами диапазонов и частичными совпадениями и страдает от коллизий, которые приходится разрешать специальными техниками. Итоговые ограничения:

3.4. GiST

GiST (Generalized Search Tree, обобщённое поисковое дерево) — техника индексирования для сложных типов данных, например геометрических объектов.

Обобщённое поисковое дерево GiST

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

GiST часто используется для индексации пространственных данных — например, в PostGIS, расширении PostgreSQL. Он особенно полезен для запросов с геометрическими отношениями: поиск объектов в радиусе, пересечение областей и другие пространственные запросы.

Для создания индекса необходим один столбец, поэтому многомерные координаты преобразуются в одномерные. Один из эффективных методов — кривая Гильберта: пространство-заполняющая кривая, сохраняющая близость точек многомерного пространства.

Построение кривой Гильберта
Кривая Гильберта заполняет пространство

Недостатки GiST:

3.5. Гонка индексов

Почему индекс так ускоряет поиск? В отсортированном наборе значение можно искать делением диапазона пополам — как в B-дереве, — а без индекса приходится читать строки подряд. Запустите гонку: обе стратегии ищут одно и то же значение в таблице из 64 строк, счётчики показывают число сравнений. Попробуйте несколько целей — предельный выигрыш индекса растёт с размером таблицы как N / log₂N.

Тренажёр: полное сканирование против B-дерева
полное сканирование (без индекса) · сравнений: 0
двоичный поиск по отсортированному индексу (идея B-дерева) · сравнений: 0

Значения 1–64 условны и отсортированы; в реальном B-дереве узлы хранят десятки ключей, поэтому дерево ещё мельче: миллион строк — 3–4 уровня.

4. Использование индексов: пять сценариев

Рассмотрим пять примеров использования индексов PostgreSQL в реальных сценариях — с кодом таблицы, индексов и пояснением.

4.1. Онлайн-магазин

В онлайн-магазине есть таблица orders с информацией о заказах. Пользователи ищут заказы по customer_id, order_date и status — создадим индексы для этих столбцов:

CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  customer_id INT NOT NULL,
  order_date DATE NOT NULL,
  status VARCHAR(15) NOT NULL
);

CREATE INDEX ix_orders_customer_id ON orders (customer_id);
CREATE INDEX ix_orders_order_date ON orders (order_date);
CREATE INDEX ix_orders_status ON orders (status);

4.2. Система управления документацией

Таблица documents: поиск по title, author_id, creation_date, а для содержимого — полнотекстовый GIN-индекс:

CREATE TABLE documents (
  id SERIAL PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  author_id INT NOT NULL,
  creation_date DATE NOT NULL,
  content TEXT NOT NULL
);

CREATE INDEX ix_documents_title ON documents (title);
CREATE INDEX ix_documents_author_id ON documents (author_id);
CREATE INDEX ix_documents_creation_date ON documents (creation_date);

-- полнотекстовый индекс для столбца content
CREATE INDEX ix_documents_content ON documents
  USING gin(to_tsvector('english', content));

4.3. Система управления проектами

Таблица tasks: поиск задач по проекту, исполнителю и сроку:

CREATE TABLE tasks (
  id SERIAL PRIMARY KEY,
  project_id INT NOT NULL,
  assigned_to INT NOT NULL,
  due_date DATE NOT NULL,
  description TEXT NOT NULL
);

CREATE INDEX ix_tasks_project_id ON tasks (project_id);
CREATE INDEX ix_tasks_assigned_to ON tasks (assigned_to);
CREATE INDEX ix_tasks_due_date ON tasks (due_date);

4.4. Социальная сеть

Таблица friendships с дружескими связями; составной первичный ключ и индексы по обоим участникам связи:

CREATE TABLE friendships (
  user_id INT NOT NULL,
  friend_id INT NOT NULL,
  since_date DATE NOT NULL,
  PRIMARY KEY (user_id, friend_id)
);

CREATE INDEX ix_friendships_user_id ON friendships (user_id);
CREATE INDEX ix_friendships_friend_id ON friendships (friend_id);

4.5. Геоинформационная система

В ГИС есть таблица locations с географическими данными. Для пространственных запросов к столбцу geom создаётся GiST-индекс:

CREATE TABLE locations (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  geom GEOMETRY(Point, 4326) NOT NULL
);

-- геометрический индекс для столбца geom
CREATE INDEX ix_locations_geom ON locations USING gist(geom);

С этим индексом мы встретимся в практике 3: PostGIS создаёт GiST-индексы для геометрических столбцов, ускоряя ST_Intersects, ST_DWithin и другие пространственные предикаты.

Контрольные вопросы

Источники

  1. Дейт, К. Дж. Введение в системы баз данных / К. Дж. Дейт. — 8-е изд. — М. : Вильямс, 2005. — 1328 с.
  2. PostgreSQL 15 Documentation. Chapter 11. Indexes : [сайт]. — URL: https://www.postgresql.org/docs/15/indexes.html (дата обращения: 18.08.2026).
  3. Рогов, Е. В. PostgreSQL изнутри / Е. В. Рогов. — М. : ДМК Пресс, 2022. — 660 с.
  4. PostGIS Documentation. Spatial Indexing : [сайт]. — URL: https://postgis.net/workshops/postgis-intro/indexing.html (дата обращения: 18.08.2026).