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

Приведи пример аномалии в БД

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

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

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

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

Аномалии в базах данных

Что такое аномалия БД

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

Аномалия удаления (Deletion Anomaly)

При удалении записи теряется информация, которая не является основным предметом удаления.

Пример плохой схемы

-- Таблица: STUDENTS
STUDENT_ID | NAME     | COURSE_NAME         | INSTRUCTOR
-----------|----------|---------------------|------------
1          | John     | Java Advanced       | Alex
2          | Maria    | Python Basics       | Bob
3          | John     | Python Basics       | Bob

Проблема: если удалить студента John (ID=1), теряется информация о преподавателе Alex и курсе Java Advanced!

DELETE FROM STUDENTS WHERE STUDENT_ID = 1;
-- Результат: информация о курсе и преподавателе Alex потеряна

Правильная схема (нормализованная)

STUDENTS таблица:
STUDENT_ID | NAME
-----------|-------
1          | John
2          | Maria
3          | John

COURSES таблица:
COURSE_ID | NAME            | INSTRUCTOR
----------|-----------------|------------
101       | Java Advanced   | Alex
102       | Python Basics   | Bob

ENROLLMENTS таблица:
STUDENT_ID | COURSE_ID
-----------|----------
1          | 101
2          | 102
3          | 102

Теперь можно удалить студента без потери информации о курсе:

DELETE FROM STUDENTS WHERE STUDENT_ID = 1;
-- Курс Java Advanced остаётся в таблице COURSES

Аномалия вставки (Insertion Anomaly)

Невозможно вставить данные, не имея информацию в других полях, или нужно вставлять пустые значения.

Пример проблемы

-- Таблица: PROJECTS
PROJECT_ID | PROJECT_NAME      | MANAGER_ID | MANAGER_NAME
-----------|-------------------|------------|---------------
1          | Mobile App        | 101        | John
2          | Web Portal        | 102        | Maria

Проблема: хотим добавить нового проекта, но обязательно нужно указать manager. Если менеджер ещё не назначен, что вставлять?

// Невозможно вставить!
String sql = "INSERT INTO PROJECTS (PROJECT_ID, PROJECT_NAME) VALUES (?, ?)";
// Ошибка: MANAGER_ID и MANAGER_NAME обязательны!

Решение через нормализацию

PROJECTS таблица:
PROJECT_ID | PROJECT_NAME | MANAGER_ID
-----------|---------------|-----------
1          | Mobile App    | 101
2          | Web Portal    | 102
3          | API Service   | NULL  -- Теперь можно добавить без менеджера

MANAGERS таблица:
MANAGER_ID | MANAGER_NAME
-----------|---------------
101        | John
102        | Maria

Теперь вставка работает:

String sql = "INSERT INTO PROJECTS (PROJECT_ID, PROJECT_NAME, MANAGER_ID) VALUES (?, ?, ?)";
// MANAGER_ID может быть NULL

Аномалия обновления (Update Anomaly)

Обновление одного значения требует обновления множества других строк, иначе возникает противоречие.

Пример противоречия

-- Таблица: EMPLOYEE_DEPARTMENTS (плохая схема)
EMP_ID | EMP_NAME | DEPT_ID | DEPT_NAME      | BUDGET
-------|----------|---------|----------------|---------
1      | John     | 10      | Engineering    | 100000
2      | Maria    | 10      | Engineering    | 100000
3      | Bob      | 20      | Sales          | 50000
4      | Alice    | 10      | Engineering    | 100000

Проблема: если бюджет отдела Engineering меняется, нужно обновить все три строки (1, 2, 4):

// Требуется множественное обновление
String sql = "UPDATE EMPLOYEE_DEPARTMENTS SET BUDGET = ? WHERE DEPT_ID = ?";

// Если забыть одну строку - данные противоречивы!
// John: бюджет 100000, Maria: бюджет 120000 (для одного отдела!)

Правильное решение

EMPLOYEES таблица:
EMP_ID | EMP_NAME | DEPT_ID
-------|----------|----------
1      | John     | 10
2      | Maria    | 10
3      | Bob      | 20
4      | Alice    | 10

DEPARTMENTS таблица:
DEPT_ID | DEPT_NAME      | BUDGET
--------|----------------|---------
10      | Engineering    | 100000
20      | Sales          | 50000

Теперь обновление просто:

// Одно обновление — одна строка
String sql = "UPDATE DEPARTMENTS SET BUDGET = ? WHERE DEPT_ID = ?";
ps.setInt(1, 120000);
ps.setInt(2, 10);
ps.executeUpdate();
// Все сотрудники отдела автоматически видят новый бюджет через JOIN

Главное правило

Аномалии возникают из-за денормализации — хранения данных, которые зависят друг от друга, в одной таблице. Решение: применить нормализацию (Normal Forms):

  • 1NF (First Normal Form): Атомарные значения
  • 2NF (Second Normal Form): Нет частичных зависимостей
  • 3NF (Third Normal Form): Нет транзитивных зависимостей

Большинство практических систем используют 3NF, что исключает большинство аномалий.