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

Какие знаешь формы баз данных?

2.0 Middle🔥 91 комментариев
#Базы данных и SQL

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

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

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

Какие знаю формы баз данных:

Нормальные формы (Normal Forms) в SQL

Нормальные формы нужны чтобы избежать аномалий при обновлении данных и избыточности. Существует 5+ форм, но на практике используют первые три.

0-я нормальная форма (Unnormalized Data)

Проблема: Данные хранятся "как есть" без структуры.

Таблица Students:
|ID | Name    | Courses                         |
|----|---------|--------------------------------|
|1  | Alice   | Math, Physics, Chemistry        |
|2  | Bob     | English, History                |

Проблемы:

  • Нельзя искать всех, кто учит Math (нужен LIKE)
  • Нельзя удалить курс без обновления всех строк
  • Избыточность данных

1NF (First Normal Form) — Атомарные значения

Правило: Каждое поле должно содержать только атомарное (неделимое) значение.

Решение: Создаем отдельную таблицу для many-to-many.

CREATE TABLE students (
  id INT PRIMARY KEY,
  name VARCHAR(100)
);

CREATE TABLE courses (
  id INT PRIMARY KEY,
  course_name VARCHAR(100)
);

CREATE TABLE enrollments (
  student_id INT REFERENCES students(id),
  course_id INT REFERENCES courses(id),
  PRIMARY KEY (student_id, course_id)
);

Теперь можно запросить всех студентов на Physics:

SELECT s.name FROM students s
JOIN enrollments e ON s.id = e.student_id
JOIN courses c ON e.course_id = c.id
WHERE c.course_name = 'Physics';

2NF (Second Normal Form) — Зависимость от PRIMARY KEY

Правило: Все атрибуты должны зависеть от ВСЕГО первичного ключа, не от его части.

Проблема (до 2NF):

CREATE TABLE enrollments (
  student_id INT,
  course_id INT,
  student_name VARCHAR(100),  -- Зависит только от student_id!
  course_name VARCHAR(100),   -- Зависит только от course_id!
  grade CHAR(1),              -- Зависит от обоих (правильно)
  PRIMARY KEY (student_id, course_id)
);

Проблемы:

  • Если студент сменил имя, нужно обновлять несколько строк
  • Можно добавить студента без курса? Нет!
  • Аномалия удаления: удалим последний курс студента — потеряем его имя

Решение (2NF):

CREATE TABLE students (
  id INT PRIMARY KEY,
  name VARCHAR(100)  -- Зависит только от id
);

CREATE TABLE courses (
  id INT PRIMARY KEY,
  name VARCHAR(100)  -- Зависит только от id
);

CREATE TABLE enrollments (
  student_id INT REFERENCES students(id),
  course_id INT REFERENCES courses(id),
  grade CHAR(1),  -- Зависит от обоих ключей
  PRIMARY KEY (student_id, course_id)
);

3NF (Third Normal Form) — Транзитивная зависимость

Правило: Атрибуты не должны зависеть от других атрибутов (только от PRIMARY KEY).

Проблема (до 3NF):

CREATE TABLE employees (
  id INT PRIMARY KEY,
  name VARCHAR(100),
  department_id INT,
  department_name VARCHAR(100),  -- Зависит от department_id, не от id!
  manager_name VARCHAR(100)      -- Зависит от department_id, не от id!
);

Проблемы:

  • Если переименуем отдел, нужно обновить все сотрудники
  • Можно добавить сотрудника с department_id, которого нет?

Решение (3NF):

CREATE TABLE employees (
  id INT PRIMARY KEY,
  name VARCHAR(100),
  department_id INT REFERENCES departments(id)
);

CREATE TABLE departments (
  id INT PRIMARY KEY,
  name VARCHAR(100),
  manager_id INT REFERENCES employees(id)
);

Теперь каждый атрибут зависит ТОЛЬКО от PRIMARY KEY.

BCNF (Boyce-Codd Normal Form) — Строгая 3NF

Правило: Каждый детерминант должен быть candidate key.

Пример (редко нужна на практике):

-- Профессоры учат курсы, каждая комбинация professor-course уникальна
CREATE TABLE professor_course (
  professor_id INT,
  course_id INT,
  time VARCHAR(20),
  PRIMARY KEY (professor_id, course_id, time)
);

Если professor_id → time (профессор всегда в одно время), это нарушает BCNF. Решение: отдельная таблица.

4NF / 5NF — Мультизначные и связанные зависимости

Эти формы очень редки на практике. Используются только в сложных аналитических системах.

Практические рекомендации

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

Не всегда нужно максимальная нормализация. Денормализация может помочь:

  1. Кэширование часто запрашиваемых данных:
-- Денормализованный подсчет (кэш)
CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(100),
  post_count INT DEFAULT 0  -- Кэш количества постов
);

-- При добавлении поста обновляем кэш:
UPDATE users SET post_count = post_count + 1 WHERE id = ?;
  1. Денормализованные отчеты:
-- 3NF таблицы для продаж
SELECT customer.name, product.price, order.quantity
FROM orders
JOIN customers ON orders.customer_id = customers.id
JOIN products ON orders.product_id = products.id;

-- Денормализованная таблица для аналитики (материализованное представление)
CREATE MATERIALIZED VIEW sales_report AS
SELECT customer_name, product_name, price * quantity as total
FROM ...

Таблица сравнения

ФормаПравилоПлюсыМинусы
1NFАтомарные значенияУбирает повторенияМожет потребоваться больше таблиц
2NFОт полного PRIMARY KEYАномалии на одну таблицу меньшеБольше JOIN'ов
3NFНет транзитивных зависимостейЧистая структураСложно запрашивать
BCNFВсе детерминанты = candidate keysМаксимально чистоНа практике редко нужна

Примеры в Node.js + TypeORM

// 3NF: students и courses в отдельных таблицах
@Entity()
export class Student {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @ManyToMany(() => Course, course => course.students)
  @JoinTable()
  courses: Course[];
}

@Entity()
export class Course {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @ManyToMany(() => Student, student => student.courses)
  students: Student[];
}

Главное: Нормализуй до 3NF по умолчанию, денормализуй только если есть реальные проблемы производительности.

Какие знаешь формы баз данных? | PrepBro