Что такое нормализация баз данных, какие нормальные формы вы знаете и зачем она нужна?

Ответ

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

Основная цель — разбить большие таблицы на меньшие, хорошо структурированные таблицы и определить связи между ними.

Основные нормальные формы (НФ):

  1. Первая нормальная форма (1НФ):

    • Таблица является "плоской".
    • Все атрибуты (колонки) являются атомарными (неделимыми), то есть в одной ячейке не может быть нескольких значений.
    • Отсутствуют повторяющиеся группы столбцов (например, product1, product2).
  2. Вторая нормальная форма (2НФ):

    • Таблица находится в 1НФ.
    • Все неключевые атрибуты полностью зависят от составного первичного ключа. Если первичный ключ простой (состоит из одного поля), таблица в 1НФ автоматически находится и во 2НФ.
  3. Третья нормальная форма (3НФ):

    • Таблица находится в 2НФ.
    • Отсутствуют транзитивные зависимости. Это означает, что неключевые атрибуты не должны зависеть от других неключевых атрибутов.

Существуют и другие формы (НФ Бойса-Кодда, 4НФ, 5НФ), но на практике чаще всего достаточно приведения к 3НФ.

Пример:

Предположим, у нас есть таблица заказов: Orders (OrderID, CustomerID, CustomerName, ProductID, ProductName, Quantity)

  • Проблема: CustomerName зависит от CustomerID, а ProductName — от ProductID. Это вызывает избыточность (имя клиента повторяется для каждого его заказа) и аномалии обновления (если клиент сменит имя, придется обновить все его заказы).

  • Решение (приведение к 3НФ):

    1. Customers (CustomerID, CustomerName)
    2. Products (ProductID, ProductName)
    3. Orders (OrderID, CustomerID, ProductID, Quantity)

Компромиссы и денормализация:

  • Преимущества нормализации: целостность данных, отсутствие избыточности, гибкость.
  • Недостаток: для получения полных данных требуется больше операций JOIN, что может снижать производительность на больших объемах данных.

В некоторых случаях для повышения скорости чтения данных применяют денормализацию — умышленное нарушение нормальных форм для объединения данных в одной таблице и уменьшения количества JOIN'ов.

Ответ 18+ 🔞

Давай я тебе на пальцах объясню, что за зверь такой — нормализация баз данных. Представь, что ты ведёшь учёт заказов в одной здоровенной таблице, как какой-нибудь древний купец в амбарной книге. И записываешь туда всё подряд: номер заказа, айдишник клиента, его имя, айдишник товара, название товара и количество. Вроде бы логично, да?

А теперь смотри, что получается, ёпта. У тебя клиент «Василий Пупкин» сделал 50 заказов. И его имя «Василий Пупкин» ты благополучно вписал 50 раз, один в один. Избыточность, блядь, овердохуища! А потом этот Василий возьми и смени имя на «Василиса». И что, тебе теперь во всех 50 строчках его имя менять? Да я с ума сойду! Это ж аномалия обновления, пиздец просто. Или удалишь заказ — и хуй с ним, данные целы. А вот если удалишь последний заказ клиента, то и информация о самом клиенте — его айди и имя — нахуй пропадает из системы. Во все дыры давалка получается, а не база данных.

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

Первая нормальная форма (1НФ) — это как базовый уровень гигиены. Таблица должна быть плоской, а в каждой клеточке — одно значение. Никаких списков через запятую в одной ячейке, типа «Молоко, Хлеб, Селедка». И никаких повторяющихся колонок, вроде Товар1, Товар2, Товар3. Это же пиздопроебищно, ну правда.

Вторая нормальная форма (2НФ) уже хитрее. Она требует, чтобы все неключевые поля (те, что не входят в первичный ключ) зависели от ВСЕГО составного ключа, а не от его кусочка. Если ключ простой — то всё ок.

Но главный кайф — это Третья нормальная форма (3НФ). Её суть в том, чтобы не было вот этих вот транзитивных зависимостей, блядь. Грубо говоря, чтобы неключевые поля зависели ТОЛЬКО от первичного ключа, а не друг от друга. В нашем примере CustomerName зависит не от ключа заказа, а от CustomerID. Это нарушение, ёперный театр! Значит, надо выносить.

И вот как мы это лечим, хитрая жопа:

  1. Заводим отдельную табличку Customers только для клиентов: CustomerID и CustomerName.
  2. Отдельную табличку Products для товаров: ProductID и ProductName.
  3. А в основной таблице Orders оставляем только сухие факты: OrderID, CustomerID, ProductID, Quantity.

Теперь всё красиво. Имя клиента хранится в одном-единственном месте. Сменил Василий имя — обновил одну запись. Удалили все заказы — информация о клиенте осталась. Красота, блядь!

Но и тут не без подлянки. Когда тебе нужно сформировать отчёт «что купил Василий», тебе придётся склеить (JOIN) аж три таблицы. И если данных — хуева туча, эти соединения могут тормозить, как черепаха в сиропе.

Поэтому иногда, особенно в аналитических базах (хранилищах данных), идут на денормализацию — умышленно нарушают эти правила и снова сваливают всё в кучу, чтобы меньше соединять. Это осознанный компромисс: жертвуем аккуратностью обновления ради скорости чтения. Но это уже, как говорится, совсем другая история, и подходить к этому надо с умом, а не с хуя.