Введение в проектирование
Зачем проектировать
Плохая схема БД — источник проблем на годы:
- Медленные запросы — нет индексов, денормализация вслепую.
- Дубли данных — обновляешь в трёх местах, забываешь в четвёртом.
- Сложные JOIN — 5+ таблиц на каждый запрос.
- Невозможность изменить — каждое изменение = миграция данных.
- Баги консистентности — данные противоречат друг другу.
Что даёт хорошее проектирование:
- Быстрые запросы.
- Простые изменения.
- Гарантии целостности.
- Понятная структура.
Правило: 1 час проектирования экономит 10 часов рефакторинга.
Три уровня модели
1. Концептуальная (Conceptual):
- Что вообще есть в предметной области.
- Сущности и их связи.
- Без деталей реализации.
Клиент — заказывает — Товар
2. Логическая (Logical):
- Атрибуты сущностей.
- Типы (абстрактные).
- Ключи.
- Нормализация.
- Без привязки к СУБД.
Клиент(id, email, имя) — Заказ(id, клиент_id, дата) — Товар(id, название, цена)
3. Физическая (Physical):
- Конкретная СУБД (PostgreSQL, MySQL).
- Типы данных (BIGINT, VARCHAR, TIMESTAMPTZ).
- Индексы, партиции.
- Оптимизации.
CREATE TABLE customers (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
name TEXT NOT NULL
);
Этапы проектирования
7 шагов:
1. Сбор требований. Что должна система делать?
2. Выделение сущностей. Что есть в мире?
3. Определение связей. Как сущности связаны?
4. Атрибуты. Какие данные у каждой сущности?
5. Ключи. Как идентифицировать записи?
6. Нормализация. Убрать дубликаты и аномалии.
7. Денормализация и индексы. Оптимизация под запросы.
Сбор требований
Что спросить:
- Какие данные хранится? Список сущностей.
- Какие операции? CRUD, отчёты, поиск.
- Объёмы? 100 строк или 100 млн.
- Паттерны доступа? Читают или пишут.
- Целостность? Что нельзя нарушать.
- История? Нужны ли старые версии.
Артефакты:
- ТЗ — текстовое описание.
- Use cases — сценарии.
- ER-диаграмма — визуализация.
Пример: интернет-магазин
Требования:
- Клиенты регистрируются, оставляют заказы.
- Товары в категориях.
- Заказ содержит несколько товаров.
- Есть остатки на складе.
- История заказов сохраняется.
Сущности:
- Клиент.
- Товар.
- Категория.
- Заказ.
- Позиция заказа.
Связи:
- Клиент 1:N Заказ.
- Категория 1:N Товар.
- Заказ N:N Товар (через Позиция).
ER-диаграмма
Три элемента:
- Сущность — прямоугольник.
- Атрибут — овал или поле внутри.
- Связь — ромб или линия.
Нотация Crow's Foot (вороньи лапки):
[Клиент] ||──o{ [Заказ]
Что означает:
||— одна сторона (ровно один).o{— много (ноль или больше).o|— ноль или один.|{— один или больше.
Инструменты:
- dbdiagram.io — простой онлайн.
- draw.io — бесплатный.
- Mermaid — в markdown.
- DBeaver, DataGrip — из схемы.
Mermaid-пример:
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ ORDER_ITEM : contains
PRODUCT ||--o{ ORDER_ITEM : "in"
CATEGORY ||--o{ PRODUCT : contains
Идентификаторы
Что использовать:
- Суррогатный ключ — автоинкремент, UUID. Не зависит от бизнеса.
- Естественный ключ — email, ISBN, ИНН. Значимый.
Правило: всегда суррогатный PK + уникальный индекс на естественный.
Почему:
- Естественный ключ может измениться (email поменяли).
- Суррогатный — компактный (BIGINT 8 байт).
- Меньше риск при merge.
Пример:
CREATE TABLE users (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
...
);
Типы связей
1-к-1 (1:1):
- Редко.
- Выделение редких полей.
- Разделение по правам.
1-к-N (1:N):
- Основной тип.
- FK в дочерней таблице.
N-к-N (N:N):
- Через связующую таблицу.
- Составной PK.
- Может содержать свои атрибуты (например, дата добавления в корзину).
Практика
1. Возьмите свой проект. Определите сущности.
2. Нарисуйте ER-диаграмму (dbdiagram.io или draw.io).
3. Определите связи. Какие 1:1, 1:N, N:N?
4. Выберите PK для каждой таблицы.
5. Определите базовые атрибуты.
Итог
- Проектирование экономит время.
- 3 уровня: концептуальный, логический, физический.
- 7 этапов от требований до денормализации.
- Суррогатный PK + естественный UNIQUE.
- ER-диаграмма — обязательный артефакт.
- Crow's Foot — популярная нотация.
Дальше — нормализация: 1NF, 2NF, 3NF.