← Назад к вопросам

Как должны храниться данные в третьей форме?

2.3 Middle🔥 191 комментариев
#Архитектура и паттерны#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как должны храниться данные в третьей нормальной форме (3NF)

Третья нормальная форма (3NF) — это состояние базы данных, при котором исключены все аномалии обновлений и удаления, а также обеспечена целостность данных через правильное разделение таблиц и использование внешних ключей.

Предпосылки для 3NF

Прежде чем достичь третьей нормальной формы, база должна удовлетворять:

  • Первая нормальная форма (1NF) — атомарные значения (нет массивов/вложенных таблиц)
  • Вторая нормальная форма (2NF) — нет частичной зависимости от составного ключа

Правило третьей нормальной формы

Третья нормальная форма требует:

  1. Каждый неключевой атрибут зависит только от первичного ключа
  2. Нет транзитивных зависимостей (когда неключевой атрибут зависит от другого неключевого атрибута)
Правильно: Атрибут -> Первичный ключ
Неправильно: Атрибут -> Другой атрибут -> Первичный ключ

Пример нарушения 3NF

Плохо (не соответствует 3NF)

Таблица студентов с информацией о факультете:

студенты
├── student_id (первичный ключ)
├── name
├── department_id
├── department_name (Зависит от department_id, не от student_id!)
└── department_head

Проблемы:

  • Дублирование данных — одно и то же имя факультета повторяется для каждого студента
  • Аномалия обновления — если изменить название факультета, нужно обновить все строки студентов
  • Аномалия удаления — если удалить всех студентов факультета, потеряем информацию о факультете

Хорошо (соответствует 3NF)

Отдельные таблицы:

студенты                    факультеты
├── student_id             ├── department_id
├── name                   ├── name
└── department_id -------> ├── head
                           └── ...

Практический пример: интернет-магазин

Денормализованная структура (плохо)

// Одна таблица со всем
CREATE TABLE orders (
  order_id INT PRIMARY KEY,
  customer_name VARCHAR(100),
  customer_email VARCHAR(100),
  customer_phone VARCHAR(20),
  customer_city VARCHAR(100),
  
  product_id INT,
  product_name VARCHAR(100),
  product_price DECIMAL(10,2),
  product_category VARCHAR(100),
  
  quantity INT,
  order_date TIMESTAMP
);

Проблемы:

  • Информация о клиенте повторяется в каждом заказе
  • Информация о товаре повторяется для каждого заказа
  • Если изменить цену товара, нужно обновить все заказы

Нормализованная структура (хорошо, 3NF)

// Таблица клиентов
CREATE TABLE customers (
  customer_id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(100) UNIQUE,
  phone VARCHAR(20),
  city VARCHAR(100)
);

// Таблица товаров
CREATE TABLE products (
  product_id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  price DECIMAL(10,2) NOT NULL,
  category_id INT,
  FOREIGN KEY (category_id) REFERENCES categories(category_id)
);

// Таблица категорий
CREATE TABLE categories (
  category_id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL
);

// Таблица заказов
CREATE TABLE orders (
  order_id SERIAL PRIMARY KEY,
  customer_id INT NOT NULL,
  order_date TIMESTAMP DEFAULT NOW(),
  total_amount DECIMAL(10,2),
  FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

// Таблица позиций заказа (связь)
CREATE TABLE order_items (
  order_item_id SERIAL PRIMARY KEY,
  order_id INT NOT NULL,
  product_id INT NOT NULL,
  quantity INT NOT NULL,
  price_at_purchase DECIMAL(10,2) NOT NULL,
  FOREIGN KEY (order_id) REFERENCES orders(order_id),
  FOREIGN KEY (product_id) REFERENCES products(product_id)
);

Преимущества:

  • Нет дублирования — информация хранится в одном месте
  • Легко обновлять — изменения обновляют только одну таблицу
  • Целостность — внешние ключи гарантируют корректность данных

Ключевые принципы 3NF

1. Первичные ключи

Каждая таблица должна иметь уникальный первичный ключ:

CREATE TABLE users (
  user_id SERIAL PRIMARY KEY,
  email VARCHAR(100) UNIQUE,
  name VARCHAR(100)
);

2. Внешние ключи

Для связей между таблицами используются внешние ключи:

CREATE TABLE posts (
  post_id SERIAL PRIMARY KEY,
  user_id INT NOT NULL,
  title VARCHAR(255),
  content TEXT,
  FOREIGN KEY (user_id) REFERENCES users(user_id)
);

3. Минимизация дублирования

// Плохо: одинаковые данные в разных таблицах
users (user_id, email, city_name, city_zip_code)
cities (city_id, city_name, city_zip_code) // дублирование!

// Хорошо: ссылка на единый источник
users (user_id, email, city_id)
cities (city_id, name, zip_code)

4. Избегание транзитивных зависимостей

// Плохо: author_country зависит от author, не от book
books (
  book_id,
  title,
  author_id,
  author_name,
  author_country // транзитивная зависимость!
)

// Хорошо: разные таблицы
books (book_id, title, author_id)
authors (author_id, name, country)

Когда денормализовать?

Хотя 3NF — это идеальная цель, иногда стратегическая денормализация допустима:

// Приемлемо: кэширование часто используемых данных
CREATE TABLE order_summaries (
  order_id INT PRIMARY KEY,
  customer_name VARCHAR(100), // кэш для быстрого доступа
  total_amount DECIMAL(10,2),
  FOREIGN KEY (order_id) REFERENCES orders(order_id)
);

Причины для денормализации:

  • Производительность — уменьшение количества JOIN'ов
  • Часто читаемые данные — быстрее доступ

Но это должно быть осознанным выбором, не забывая синхронизировать кэшированные данные.

Итоги

В третьей нормальной форме:

  • Каждый неключевой атрибут зависит только от первичного ключа
  • Нет транзитивных зависимостей между неключевыми атрибутами
  • Данные распределены по связанным таблицам
  • Внешние ключи обеспечивают целостность
  • Минимум дублирования и аномалий обновления

3NF — это стандарт для production баз данных и обеспечивает целостность, масштабируемость и легкость поддержания.