SQL vs NoSQL: таблицы и связи, ACID, документы, ключ-значение и как выбрать базу под задачу.
Реляционная БД (PostgreSQL, MySQL, SQLite) хранит данные в таблицах со строгой схемой: заранее известно, какие колонки есть и какого они типа.
Возьмём магазин. Наивно можно хранить заказ одной строкой:
| id | customer | items |
|----|-------------------|--------------------------------|
| 1 | Аня, anya@mail.ru | Ноутбук x1, Мышь x2 |
| 2 | Аня, anya@mail.ru | Клавиатура x1 |Проблемы: email Ани продублирован (изменится — обновлять везде), а items — строка, по которой нельзя ни посчитать, ни отфильтровать.
Нормализация — раскладываем данные так, чтобы каждый факт хранился один раз:
users orders order_items
| id | name | email | | id | user_id | at | | order_id | product_id | qty |Таблицы ссылаются друг на друга через внешние ключи (foreign key): orders.user_id → users.id. Целостность охраняет сама база: нельзя создать заказ несуществующего пользователя.
orders.user_id)order_items)Собираем всё обратно оператором JOIN — за это реляционные БД и любят: любые срезы данных без изменения схемы. 💪
-- Схема магазина: каждый факт хранится один раз
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL REFERENCES users(id),
created_at TIMESTAMP DEFAULT now()
);
CREATE TABLE order_items (
order_id INT REFERENCES orders(id),
product_id INT REFERENCES products(id),
qty INT NOT NULL CHECK (qty > 0)
);
-- Все заказы Ани с товарами — одним запросом
SELECT o.id, p.title, oi.qty
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON p.id = oi.product_id
JOIN users u ON u.id = o.user_id
WHERE u.email = 'anya@mail.ru';Зачем нужна нормализация данных?
orders.user_id → users.id, order_items.order_id → orders.id. Каждый факт хранится один раз, целостность охраняет сама база. Собираем обратно через JOIN.