Реляционная модель данных: таблицы и ограничения
От навигационного хаоса к строгой математике
Почему индустрии в 1970 году потребовался радикальный пересмотр концепции хранения данных.
Навигационные базы 1960-х годов
В иерархических и сетевых СУБД (CODASYL, IMS) данные соединялись физическими указателями на дисковые блоки. Программист писал императивный код («перейти по указателю X к записи Y»). Любая реорганизация диска ломала прикладные программы.
Прорыв Эдгара Кодда (IBM, 1970)
Эдгар Франк Кодд предложил абстрагировать логический уровень от физического. Единственная структура представления данных для пользователя и разработчика — математическое отношение (таблица). Связи строятся на совпадении значений данных, а не на скрытых указателях.
Терминологический мост: теория РМД vs практика SQL
Точное соответствие математического аппарата Э. Кодда и промышленного диалекта SQL.
| Теория РМД (Э. Кодд) | Инженерная практика (SQL) | Смысл понятия |
|---|---|---|
| Отношение (Relation) | Таблица (Table) | Поименованное двумерное множество кортежей над доменами |
| Кортеж (Tuple) | Строка / Запись (Row) | Единичный экземпляр сущности со значениями всех атрибутов |
| Атрибут (Attribute) | Столбец / Поле (Column) | Именованная характеристика, определенная на некотором домене |
| Домен (Domain) | Тип данных + CHECK | Множество всех допустимых потенциальных скалярных значений |
Анатомия отношения: заголовок и тело
Разделение схемы данных (метаданных) и текущего фактического содержимого.
Заголовок отношения (Heading / Schema)
Фиксированное множество пар вида <Имя_атрибута : Имя_домена>.
Заголовок задается инженером при проектировании через операторы DDL (CREATE TABLE). Он неизменен во время обычных транзакций вставки или чтения данных.
Тело отношения (Body / Instance)
Динамическое множество кортежей, удовлетворяющих заголовку в данный момент времени.
Тело непрерывно модифицируется DML-запросами (INSERT, UPDATE, DELETE), отражая актуальное состояние предметной области предприятия.
Метрики отношения: арность и мощность
Количественные характеристики структуры и наполнения таблицы.
Степень / Арность (Degree / Arity)
Количество атрибутов (столбцов) в заголовке отношения.
- 1 атрибут — унарное отношение;
- 2 атрибута — бинарное отношение;
- n атрибутов — n-арное отношение.
Свойство: Статическая величина схемы базы данных.
Кардинальность / Мощность (Cardinality)
Количество кортежей (строк) в теле отношения на текущий момент времени t.
Если в таблице студентов числится 120 человек, ее мощность равна 120. Мощность пустого отношения равна 0.
Свойство: Динамическая величина, меняющаяся с каждой транзакцией.
4 фундаментальных свойства отношений
Математические законы теории множеств, определяющие поведение реляционных таблиц.
1. Уникальность кортежей
В множестве не может быть двух одинаковых элементов. Каждая строка таблицы обязана быть уникальной и однозначно идентифицироваться первичным ключом.
2. Отсутствие порядка строк
Порядок строк математически неопределен. Физический порядок чтения с диска произволен. Сортировка задается строго оператором ORDER BY в запросе.
3. Отсутствие порядка столбцов
Столбцы не нумеруются. Каждый атрибут адресуется строго по уникальному имени в заголовке. Перестановка колонок не меняет отношение.
4. Атомарность значений (1НФ)
Все значения в ячейках должны быть неделимыми скалярами. Никаких списков, вложенных массивов или составных строк через запятую в одной ячейке!
Первая нормальная форма (1НФ): атомарность
Отказ от повторяющихся групп и неструктурированных списков внутри ячеек.
Нарушение 1НФ (Антипаттерн)
Хранение списка телефонов в одной текстовой строке:
ID: 101 | Name: Иванов Phones: "+7912..., +7902..., +7982..."
Последствия: Невозможно создать B-Tree индекс, невозможно быстро проверить уникальность номера, громоздкие строковые парсеры в SQL.
Реляционная нормализация (1НФ)
Декомпозиция на две связанные таблицы (1:N):
Таблица Студенты (student_id, name) Таблица Телефоны (phone_id, student_id, phone)
Результат: Каждое значение атомарно. Действуют индексы, внешние ключи и проверка формата регулярным выражением.
Система ограничений целостности (Integrity)
Декларативные предикаты, охраняющие корректность и согласованность базы данных.
Три уровня целостности
- Целостность сущности (Entity Integrity): идентификация и уникальность объектов реального мира (PRIMARY KEY).
- Ссылочная целостность (Referential Integrity): непротиворечивость связей между таблицами (FOREIGN KEY).
- Семантическая / доменная (Semantic Integrity): бизнес-правила и ограничения значений полей (CHECK, NOT NULL).
Принцип декларативности (Правило 10 Кодда)
Ограничения целостности определяются на языке DDL и сохраняются в системном каталоге СУБД, а не зашиваются в клиентский код на JavaScript/Python.
Даже если бэкенд упал или ошибся программист, ядро СУБД физически не позволит записать невалидные данные.
Целостность сущности: Primary Key и запрет NULL
Первичное правило РМД: каждый кортеж должен быть однозначно различим.
Правило целостности сущности
Ни один атрибут первичного ключа (PRIMARY KEY) не может содержать значение NULL, и все значения ключа обязаны быть строго уникальными.
NULL означает «неизвестность» или «отсутствие значения». Объект без идентификатора теряет физический смысл в системе.
Естественные vs Суррогатные ключи
Естественный ключ: реальный реквизит предметной области (VIN авто, артикул SKU, ИНН компании). Плюс: нет лишних полей. Минус: сложно обновлять при смене формата.
Суррогатный ключ: синтетическое целочисленное поле (SERIAL / BIGSERIAL / UUID). Плюс: стабильность, высокая скорость соединения (JOIN по целому числу).
Ссылочная целостность: Foreign Key
Предотвращение появления «висячих ссылок» (orphaned records) между таблицами.
Проблема «висячих ссылок»
Представьте, что из таблицы «Пациенты» удалили запись с id=42, но в таблице «Назначения» остался рецепт на введение опасного препарата пациенту 42.
Внешний ключ (FOREIGN KEY) гарантирует: значение в дочерней таблице обязано существовать в родительской, либо быть равным NULL.
Синтаксис DDL связи
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
client_id INT NOT NULL,
order_date DATE NOT NULL,
CONSTRAINT fk_orders_client
FOREIGN KEY (client_id)
REFERENCES clients(client_id)
);
Управление связностью: опции ON DELETE
Поведение ядра СУБД при попытке модификации или удаления родительской записи.
| Опция | Поведение СУБД | Рекомендуемый сценарий |
|---|---|---|
RESTRICT / NO ACTION |
Блокирует удаление родителя, возвращая ошибку нарушения FK. | Учетные и финансовые системы (нельзя удалить товар с остатками или клиента с договором). |
CASCADE |
Автоматически каскадно удаляет все связанные дочерние строки. | Зависимые подчиненные сущности (удаление заказа удаляет его позиции в чеке). |
SET NULL |
Заполняет внешний ключ в дочерних строках значением NULL. |
Смена ответственного лица (увольнение куратора оставляет поле пустым до назначения). |
SET DEFAULT |
Устанавливает в дочерних строках значение FK по умолчанию. | Перенос задач на системного дежурного администратора по умолчанию. |
Семантическая целостность: ограничение CHECK
Предикатная валидация значений на соответствие физическим законам предметной области.
Назначение CHECK
Ограничение CHECK (предикат) вычисляет булево выражение для каждой новой или обновляемой строки. Если выражение возвращает FALSE, транзакция отменяется.
Предотвращает запись бессмысленных значений: отрицательных цен, отрицательного возраста, перевернутых диапазонов дат.
Инженерные примеры CHECK
-- Неотрицательный остаток CHECK (quantity >= 0) -- Допустимый балл студента CHECK (score BETWEEN 0 AND 100) -- Диапазон дат бронирования CHECK (end_date > start_date) -- Разовая дозировка препарата (мг) CHECK (dosage_mg > 0 AND dosage_mg <= 500)
Сквозной кейс: связывание двух таблиц с защитой
Полный пример DDL-схемы отношений со всеми тремя видами целостности.
-- Родительская таблица: Товары
CREATE TABLE products (
sku VARCHAR(20) PRIMARY KEY,
name VARCHAR(150) NOT NULL,
unit_price NUMERIC(10,2) NOT NULL CHECK (unit_price > 0)
);
-- Дочерняя таблица: Складские остатки с тройной защитой целостности
CREATE TABLE inventory (
inventory_id SERIAL PRIMARY KEY,
sku VARCHAR(20) NOT NULL,
warehouse_zone VARCHAR(10) NOT NULL,
quantity INT NOT NULL DEFAULT 0,
CONSTRAINT fk_inv_product FOREIGN KEY (sku)
REFERENCES products(sku) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT chk_qty_non_negative CHECK (quantity >= 0),
CONSTRAINT uq_sku_zone UNIQUE (sku, warehouse_zone)
);
Чек-лист реляционного проектировщика
Пять обязательных правил надежности перед отправкой схемы в production.
1. Наличие первичного ключа
У каждой таблицы обязан быть PRIMARY KEY (суррогатный или естественный). Таблицы без ключа — архитектурный брак.
2. Соблюдение 1НФ
Все поля атомарны. Никаких строк с запятыми для хранения списков. Связи «один-ко-многим» выносятся в дочерние таблицы.
3. Явные внешние ключи
Любая связь оформлена через FOREIGN KEY со строгим указанием правила ON DELETE (RESTRICT или CASCADE).
4. Предикаты CHECK и NOT NULL
Бизнес-ограничения зафиксированы в DDL. База защищена от отрицательных балансов, невалидных статусов и пустых идентификаторов.
Легендарный мем индустрии: «Маленький Бобби Таблицы»
Комикс xkcd №327: «Exploits of a Mom» (автор Рэндалл Манро) — самый известный мем мировой IT-культуры о реляционных таблицах, валидации данных и SQL-инъекциях.
Мама назвала сына:
Robert'); DROP TABLE Students;--
Школа попыталась сохранить имя ученика прямой строковой конкатенацией в SQL-запрос, в результате чего реляционная СУБД выполнила команду удаления и уничтожила таблицу с оценками всех учеников за год.
Комикс: xkcd #327 "Exploits of a Mom" (автор Randall Munroe).
Лицензия: Creative Commons Attribution-NonCommercial 2.5 License (CC BY-NC 2.5).
Методический вывод: строгое определение доменов, ограничений целостности и параметризация запросов ядром СУБД — гарантия выживания информационной системы.