Ответ
Разбиение таблиц (нормализация) — это компромисс между целостностью данных и производительностью. В моей практике я применяю нормализацию осознанно, в зависимости от требований конкретного проекта.
Когда нормализация оправдана:
- Устранение аномалий данных — когда обновление должно затрагивать только одно место
- Сложные бизнес-правила — разные сущности с разными жизненными циклами
- Частые изменения структуры — легче менять небольшие таблицы
Пример нормализованной структуры для интернет-магазина:
-- Основные таблицы
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE addresses (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
address_line TEXT NOT NULL,
city VARCHAR(100) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
address_id INT NOT NULL,
status ENUM('pending', 'processing', 'shipped', 'delivered'),
total DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (address_id) REFERENCES addresses(id)
);
Когда стоит денормализовать:
- Частые аналитические запросы — денормализация ускоряет SELECT
- Системы чтения (read-heavy) — кэширование вычисленных полей
- Микросервисная архитектура — каждый сервис владеет своими данными
Мой подход:
- Начинаю с нормализованной схемы (3NF) для обеспечения целостности
- Измеряю производительность реальных запросов
- Денормализую только проблемные места, добавляя вычисляемые поля или материализованные представления
- Документирую причины денормализации в миграциях
Например, в высоконагруженном приложении я добавлял поле full_name в таблицу пользователей, хотя имя и фамилия уже хранились отдельно, чтобы избежать CONCAT в частых запросах.