Фундаментальный теоретический конспект

Дисциплина: ОП.08 Основы проектирования баз данных
Тема рабочей программы (§2.2 с.7): Тема 1. Основные понятия баз данных — Практическое занятие №1: ключи, объекты и проект БД, таблицы
Назначение: Учебный конспект студента для подготовки к практической работе, курсовому проектированию и демонстрационному экзамену

1. Реляционная таблица как основа физической модели БД

В реляционной модели данных Эдгара Кодда информация представляется в виде двумерных математических отношений, которые на физическом уровне СУБД реализуются как таблицы (Tables). Каждая строка таблицы называется записью или кортежем (Tuple), а каждый столбец — полем или атрибутом (Attribute).

К реляционной таблице предъявляются жесткие архитектурные требования:

1.1. Блок-схема логической структуры реляционной таблицы

+-----------------------------------------------------------------------------------------+ | ТАБЛИЦА: zakazy (Заказы клиентов) | +-----------------------------------------------------------------------------------------+ | ИМЯ ПОЛЯ | ТИП ДАННЫХ | ОГРАНИЧЕНИЕ ЦЕЛОСТНОСТИ | НАЗНАЧЕНИЕ | +----------------------+----------------+---------------------------+-----------------------------+ | [PK] id_zakaza | BIGINT/SERIAL | PRIMARY KEY | Суррогатный первичный ключ | | [AK] nomer_kvitancii | VARCHAR(30) | NOT NULL UNIQUE | Альтернативный естеств. ключ| | [FK] id_klienta | INT | NOT NULL REFERENCES ... | Внешний ключ (связь 1:M) | | [FK] id_mastera | INT | REFERENCES mastera(...) | Внешний ключ (факультативн.)| | status | VARCHAR(20) | NOT NULL DEFAULT 'новый' | Состояние жизненного цикла | | summa | NUMERIC(10,2) | NOT NULL CHECK (summa >=0)| Финансовое значение | | data_sozdaniya | TIMESTAMP | NOT NULL DEFAULT NOW() | Временная метка аудита | +----------------------+----------------+---------------------------+-----------------------------+ | ОГРАНИЧЕНИЯ УРОВНЯ ТАБЛИЦЫ | | CONSTRAINT chk_status CHECK (status IN ('новый', 'в_работе', 'готов', 'выдан')) | | CONSTRAINT fk_klient FOREIGN KEY (id_klienta) REFERENCES klienty(id_klienta) | | ON UPDATE CASCADE ON DELETE RESTRICT | +-----------------------------------------------------------------------------------------+

2. Теория первичных ключей: Естественные vs Суррогатные

Первичный ключ (Primary Key, PK) — это минимальный набор атрибутов, однозначно идентифицирующий кортеж в отношении. Первичный ключ эквивалентен комбинации ограничений NOT NULL и UNIQUE, а СУБД автоматически создает под него кластеризованный или уникальный B-Tree индекс.

2.1. Естественные ключи (Natural Keys)

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

2.2. Суррогатные ключи (Surrogate Keys)

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

Тип суррогатного ключа Размер Способ генерации в 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() Распределенные архитектуры, мобильные клиенты, автономный оффлайн-ввод.
Золотое правило реляционного проектирования:
1. В качестве PRIMARY KEY используйте суррогатный целочисленный идентификатор (INT или BIGINT).
2. Все естественные бизнес-идентификаторы (ИНН, VIN, номер паспорта, email) делайте альтернативными ключами через UNIQUE NOT NULL.

3. Физические типы данных в реляционных СУБД

Выбор типа данных определяет требуемый объем оперативной памяти (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'.

4. Ограничения целостности (Integrity Constraints)

Ограничения целостности представляют собой декларативные правила, которые СУБД проверяет при каждой операции INSERT, UPDATE и DELETE. Если операция нарушает хотя бы одно ограничение, транзакция прерывается с ошибкой.

4.1. Декларативные ограничения

4.2. Примеры предикатных ограничений 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)

5. Внешние ключи (Foreign Key) и ссылочная целостность

Внешний ключ (Foreign Key, FK) — это колонка или группа колонок дочерней таблицы, значения которых обязаны совпадать со значениями первичного (или уникального) ключа родительской таблицы.

РОДИТЕЛЬСКАЯ ТАБЛИЦА: avtomobili +---------------------------------------------+ | [PK] id_avto : INT (101) | <----+ | gos_nomer: VARCHAR(12) | | +---------------------------------------------+ | | Ссылочная связь ДОЧЕРНЯЯ ТАБЛИЦА: putevye_listy | (Foreign Key) +---------------------------------------------+ | | [PK] id_putevogo_lista : BIGINT | | | [FK] id_avto : INT --------------------------------+ | probeg_pri_vyezde : INT | +---------------------------------------------+

5.1. Каскадные действия при DELETE и UPDATE

Секции ON DELETE и ON UPDATE определяют поведение реляционного движка, когда запись в родительской таблице удаляется или изменяется:

6. Эталонный пример физической схемы (DDL SQL)

Ниже представлен профессиональный 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)
);

7. Вопросы для самопроверки

1. В чем заключается главное различие между суррогатным и естественным первичным ключом?

Естественный ключ формируется из реальных реквизитов предметной области (паспорт, VIN, ISBN), а суррогатный — искусственное неизменяемое числовое значение, генерируемое СУБД. Естественный ключ может измениться в реальном мире, что нарушит целостность ссылок.

2. Почему нельзя использовать тип данных FLOAT для хранения денежных средств?

Типы с плавающей точкой (FLOAT, DOUBLE) хранят числа в двоичной форме стандарта IEEE 754, что приводит к погрешностям округления при сложении дробей (например, 0.1 + 0.2 = 0.30000000000000004). Для денег используется строго NUMERIC(p,s).

3. Чем грозит указание правила ON DELETE CASCADE на внешнем ключе к таблице клиентов?

При случайном или намеренном удалении одного клиента из базы СУБД автоматически физически сотрет все его договоры, платежи, чеки и финансовые транзакции за все годы, что приведет к уничтожению юридической отчетности.

4. Почему при наличии суррогатного ID в таблице обязательно нужно добавлять ограничение UNIQUE на естественный атрибут?

Без ограничения UNIQUE СУБД позволит вставить две строки с абсолютно одинаковыми паспортами или VIN-номерами, так как их сгенерированные суррогатные ID будут разными (1 и 2). Это разрушит бизнес-логику системы.