Дисциплина: ОП.08 Основы проектирования баз данных
Тема рабочей программы (§2.2 с.7): Тема 1. Основные понятия баз данных — Практическое занятие №1: ключи, объекты и проект БД, таблицы
Назначение: Учебный конспект студента для подготовки к практической работе, курсовому проектированию и демонстрационному экзамену
В реляционной модели данных Эдгара Кодда информация представляется в виде двумерных математических отношений, которые на физическом уровне СУБД реализуются как таблицы (Tables). Каждая строка таблицы называется записью или кортежем (Tuple), а каждый столбец — полем или атрибутом (Attribute).
К реляционной таблице предъявляются жесткие архитектурные требования:
Первичный ключ (Primary Key, PK) — это минимальный набор атрибутов, однозначно идентифицирующий кортеж в отношении. Первичный ключ эквивалентен комбинации ограничений NOT NULL и UNIQUE, а СУБД автоматически создает под него кластеризованный или уникальный B-Tree индекс.
Естественный ключ формируется из реквизитов, уже существующих в реальном мире: номер паспорта гражданина, государственный номер автомобиля, ISBN печатного издания, номер ИНН организации.
INT. Поскольку первичный ключ копируется во все внешние ключи всех дочерних таблиц, размер B-Tree индексов многократно раздувается, а соединение таблиц (JOIN) замедляется.Суррогатный ключ — это искусственно созданное поле, не несущее бизнес-смысла и служащее исключительно для технической идентификации записи в рамках СУБД.
| Тип суррогатного ключа | Размер | Способ генерации в SQL | Рекомендованный сценарий |
|---|---|---|---|
INTEGER (SERIAL) |
4 байта | id INT GENERATED ALWAYS AS IDENTITY |
Справочники, каталоги, пользователи (до 2.14 млрд записей). |
BIGINT (BIGSERIAL) |
8 байт | id BIGINT GENERATED ALWAYS AS IDENTITY |
Транзакционные таблицы, журналы логов, чеки, путевые листы, бронирования. |
UUID (Universally Unique ID) |
16 байт | id UUID DEFAULT gen_random_uuid() |
Распределенные архитектуры, мобильные клиенты, автономный оффлайн-ввод. |
PRIMARY KEY используйте суррогатный целочисленный идентификатор (INT или BIGINT).UNIQUE NOT NULL.
Выбор типа данных определяет требуемый объем оперативной памяти (RAM) для кэша страниц, размер таблицы на диске и возможность использования специализированных функций фильтрации.
| Тип данных SQL | Диапазон / Формат | Корректное применение | Типичная грубая ошибка |
|---|---|---|---|
SMALLINT |
От -32 768 до +32 767 (2 байта) | Номер этажа, вместимость номера, год выпуска, стаж. | Использование для автоинкрементного ID больших таблиц. |
INTEGER (INT) |
От -2.14 млрд до +2.14 млрд (4 байта) | Первичные и внешние ключи справочников, счетчики. | Использование типа VARCHAR для числовых ID. |
BIGINT |
От $-9 \times 10^{18}$ до $+9 \times 10^{18}$ (8 байт) | Первичные ключи высоконагруженных таблиц, телеметрия. | Использование обычного INT для журналов логов. |
NUMERIC(p, s) |
Точные десятичные числа (p знаков, s после запятой) | Цены, зарплаты, остаток топлива, банковские балансы. | Использование FLOAT / REAL для денег! Приводит к потере копеек из-за двоичного округления. |
VARCHAR(n) |
Строка переменной длины до n символов | ФИО, названия, email, марки авто, статусы. | Хранение дат в виде VARCHAR(10) ('12.05.2024'). |
CHAR(n) |
Строка строго фиксированной длины n | Код валюты ISO (RUB), код страны (RU), VIN (17 симв.). | Применение для имен переменной длины (добивается пробелами). |
DATE / TIMESTAMP |
Календарная дата / Дата со временем до микросекунд | Дата заезда, дата рождения, время создания заказа. | Использование целочисленного Unix Timestamp без нужды. |
BOOLEAN |
TRUE, FALSE, NULL (1 байт) |
Флаги: активен, удален, в штате, оплачен. | Создание текстовых полей VARCHAR(5) со строками 'yes'/'no'. |
Ограничения целостности представляют собой декларативные правила, которые СУБД проверяет при каждой операции INSERT, UPDATE и DELETE. Если операция нарушает хотя бы одно ограничение, транзакция прерывается с ошибкой.
NOT NULL: запрещает хранение неопределенного значения NULL в столбце. Обязательно для всех ключевых полей, фамилий, дат событий.UNIQUE: требует уникальности каждого непустого значения. Поддерживается уникальным B-Tree индексом.DEFAULT значение: подставляет указанное константное или функциональное значение, если поле пропущено в операторе INSERT.CHECK (логическое выражение): выполняет валидацию значений столбца или строки по произвольному предикату.-- Проверка диапазона значений
CHECK (god_vypuska >= 1990 AND god_vypuska <= EXTRACT(YEAR FROM CURRENT_DATE) + 1)
-- Сравнение двух атрибутов одной строки (темпоральная целостность)
CHECK (data_vyezda > data_zaezda)
CHECK (probeg_pri_vozvrashchenii >= probeg_pri_vyezde)
-- Ограничение множества допустимых статусов
CHECK (status IN ('доступен', 'занят', 'уборка', 'ремонт'))
-- Финансовая валидация (цена продажи не ниже закупки)
CHECK (cena_prodazhi >= cena_zakupki AND cena_zakupki >= 0)
Внешний ключ (Foreign Key, FK) — это колонка или группа колонок дочерней таблицы, значения которых обязаны совпадать со значениями первичного (или уникального) ключа родительской таблицы.
Секции ON DELETE и ON UPDATE определяют поведение реляционного движка, когда запись в родительской таблице удаляется или изменяется:
RESTRICT / NO ACTION: СУБД блокирует удаление/изменение родительской строки и возвращает ошибку, если на нее ссылается хотя бы одна дочерняя строка. Используется в 90% связей учетных систем для защиты от случайного уничтожения истории.CASCADE: СУБД автоматически физически удаляет все зависимые дочерние записи. Используется строго для подчиненных спецификаций (например, пункты накладной при удалении накладной).SET NULL: СУБД заменяет значение внешнего ключа в дочерних строках на NULL (столбец внешнего ключа должен допускать NULL).SET DEFAULT: СУБД устанавливает в дочерних строках значение по умолчанию.Ниже представлен профессиональный DDL-скрипт создания связанных таблиц в СУБД PostgreSQL с соблюдением всех стандартов именования, ключей и ограничений:
-- 1. Справочник категорий номеров
CREATE TABLE kategorii_nomerov (
id_kategorii SMALLINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
nazvanie VARCHAR(50) NOT NULL UNIQUE,
vmestimost_mest SMALLINT NOT NULL CHECK (vmestimost_mest BETWEEN 1 AND 10),
bazovaya_cena_za_sutki NUMERIC(10,2) NOT NULL CHECK (bazovaya_cena_za_sutki > 0)
);
-- 2. Номерной фонд отеля
CREATE TABLE nomera (
id_nomera INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
nomer_komnaty VARCHAR(10) NOT NULL UNIQUE,
etazh SMALLINT NOT NULL CHECK (etazh BETWEEN 1 AND 50),
id_kategorii SMALLINT NOT NULL REFERENCES kategorii_nomerov(id_kategorii)
ON UPDATE CASCADE ON DELETE RESTRICT,
status VARCHAR(20) NOT NULL DEFAULT 'доступен'
CHECK (status IN ('доступен', 'занят', 'уборка', 'ремонт'))
);
-- 3. Анкеты гостей
CREATE TABLE gosti (
id_gostya INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
pasport_seriya_nomer VARCHAR(30) NOT NULL UNIQUE,
familiya VARCHAR(50) NOT NULL,
imya VARCHAR(50) NOT NULL,
otchestvo VARCHAR(50),
telefon VARCHAR(20) NOT NULL,
email VARCHAR(100),
data_rozhdeniya DATE NOT NULL
CHECK (data_rozhdeniya <= CURRENT_DATE - INTERVAL '18 years')
);
-- 4. Журнал бронирований
CREATE TABLE bronirovaniya (
id_broni BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
id_nomera INT NOT NULL REFERENCES nomera(id_nomera)
ON UPDATE CASCADE ON DELETE RESTRICT,
id_gostya INT NOT NULL REFERENCES gosti(id_gostya)
ON UPDATE CASCADE ON DELETE RESTRICT,
data_zaezda DATE NOT NULL,
data_vyezda DATE NOT NULL,
itogovaya_stoimost NUMERIC(10,2) NOT NULL CHECK (itogovaya_stoimost >= 0),
status_broni VARCHAR(20) NOT NULL DEFAULT 'создано'
CHECK (status_broni IN ('создано', 'подтверждено', 'заселен', 'завершено', 'отменено')),
sozdano_v TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT chk_dates CHECK (data_vyezda > data_zaezda)
);
Естественный ключ формируется из реальных реквизитов предметной области (паспорт, VIN, ISBN), а суррогатный — искусственное неизменяемое числовое значение, генерируемое СУБД. Естественный ключ может измениться в реальном мире, что нарушит целостность ссылок.
Типы с плавающей точкой (FLOAT, DOUBLE) хранят числа в двоичной форме стандарта IEEE 754, что приводит к погрешностям округления при сложении дробей (например, 0.1 + 0.2 = 0.30000000000000004). Для денег используется строго NUMERIC(p,s).
При случайном или намеренном удалении одного клиента из базы СУБД автоматически физически сотрет все его договоры, платежи, чеки и финансовые транзакции за все годы, что приведет к уничтожению юридической отчетности.
Без ограничения UNIQUE СУБД позволит вставить две строки с абсолютно одинаковыми паспортами или VIN-номерами, так как их сгенерированные суррогатные ID будут разными (1 и 2). Это разрушит бизнес-логику системы.