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

Зачем нужны реляционные БД?

1.3 Junior🔥 221 комментариев
#Базы данных (SQL)

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

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

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

Реляционные базы данных

Реляционные БД — это системы хранения данных, организованные в виде таблиц (отношений) с рядами и столбцами. Это наиболее распространённый тип БД, используемый в большинстве приложений. Примеры: PostgreSQL, MySQL, SQLite, Oracle, SQL Server.

Основная концепция

Данные хранятся в таблицах, связанных между собой отношениями (relations):

-- Таблица пользователей
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100) UNIQUE,
    age INT
);

-- Таблица постов
CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    user_id INT REFERENCES users(id),
    title VARCHAR(200),
    content TEXT,
    created_at TIMESTAMP
);

Визуально:

users table:          posts table:
id | name   | email  |  id | user_id | title | content
1  | Alice  | a@e.c  |  1  | 1       | Post1 | ...
2  | Bob    | b@e.c  |  2  | 1       | Post2 | ...
3  | Carol  | c@e.c  |  3  | 2       | Post3 | ...

Зачем нужны реляционные БД

1. Структурированное хранение данных:

# Вместо файла с хаотичными данными
import json

users = [
    {"id": 1, "name": "Alice", "email": "a@e.c"},
    {"id": 2, "name": "Bob", "email": "b@e.c"}
]

# Используем упорядоченную структуру в БД
import sqlite3
conn = sqlite3.connect('app.db')
cursor = conn.cursor()

# Данные организованы в таблицы с чётким схемой
cursor.execute('''
    CREATE TABLE users (
        id INTEGER PRIMARY KEY,
        name TEXT NOT NULL,
        email TEXT UNIQUE
    )
''')

2. Целостность данных:

-- Первичный ключ — гарантирует уникальность
CREATE TABLE users (
    id INTEGER PRIMARY KEY,  -- Уникален, не может быть NULL
    name TEXT NOT NULL
);

-- Внешний ключ — гарантирует связь между таблицами
CREATE TABLE posts (
    id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
    -- Нельзя добавить post с несуществующим user_id
);

-- Уникальность
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    email TEXT UNIQUE  -- Каждый email уникален
);

-- Проверка значений
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    age INTEGER CHECK (age >= 0 AND age <= 150)
);

3. Эффективное выполнение запросов:

-- SQL позволяет быстро искать, фильтровать и группировать данные

-- Найти всех пользователей старше 30 лет
SELECT * FROM users WHERE age > 30;

-- Найти посты конкретного пользователя
SELECT posts.* FROM posts 
JOIN users ON posts.user_id = users.id
WHERE users.name = 'Alice';

-- Посчитать количество постов для каждого пользователя
SELECT users.name, COUNT(posts.id) as post_count
FROM users
LEFT JOIN posts ON users.id = posts.user_id
GROUP BY users.id;

Это намного быстрее, чем загружать всё в память и обрабатывать в Python:

# Плохо — загружаем всё в память
users = load_all_users_from_file()
filtered = [u for u in users if u['age'] > 30]

# Хорошо — БД делает фильтрацию сама
cursor.execute('SELECT * FROM users WHERE age > 30')
filtered = cursor.fetchall()

4. ACID свойства:

  • Atomicity (Атомарность) — транзакция либо полностью выполнится, либо откатится
  • Consistency (Согласованность) — данные всегда в согласованном состоянии
  • Isolation (Изолированность) — параллельные транзакции не конфликтуют
  • Durability (Долговечность) — данные сохраняются даже при сбое
import sqlite3

conn = sqlite3.connect('app.db')
cursor = conn.cursor()

try:
    # Начало транзакции
    cursor.execute('BEGIN TRANSACTION')
    
    # Перевод денег
    cursor.execute('UPDATE accounts SET balance = balance - 100 WHERE id = 1')
    cursor.execute('UPDATE accounts SET balance = balance + 100 WHERE id = 2')
    
    # Если что-то пошло не так, все изменения откатываются
    conn.commit()  # Фиксируем изменения
except Exception as e:
    conn.rollback()  # Откатываем, если ошибка
    raise

5. Масштабируемость и многопользовательский доступ:

-- Несколько приложений могут работать с одной БД одновременно
-- БД управляет блокировками и конфликтами

-- Приложение 1: обновляет профиль
UPDATE users SET name = 'Alice Smith' WHERE id = 1;

-- Приложение 2: читает профиль (видит обновленные данные)
SELECT * FROM users WHERE id = 1;

Структура реляционной БД

Первичный ключ (Primary Key):

CREATE TABLE users (
    id INTEGER PRIMARY KEY,  -- Уникальный идентификатор
    name TEXT
);

Внешний ключ (Foreign Key):

CREATE TABLE posts (
    id INTEGER PRIMARY KEY,
    user_id INTEGER,
    FOREIGN KEY (user_id) REFERENCES users(id)  -- Связь с таблицей users
);

Индексы (Indexes):

-- Ускоряет поиск по email
CREATE INDEX idx_email ON users(email);

-- Теперь запрос выполнится быстрее
SELECT * FROM users WHERE email = 'alice@example.com';

Пример с Python (SQLAlchemy ORM)

from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    email = Column(String(100), unique=True)
    posts = relationship('Post', back_populates='author')

class Post(Base):
    __tablename__ = 'posts'
    
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'))
    title = Column(String(200))
    content = Column(String)
    created_at = Column(DateTime, default=datetime.utcnow)
    author = relationship('User', back_populates='posts')

# Создание БД
engine = create_engine('sqlite:///app.db')
Base.metadata.create_all(engine)

# Работа с данными
Session = sessionmaker(bind=engine)
session = Session()

# Создание пользователя
user = User(name='Alice', email='alice@example.com')
session.add(user)
session.commit()

# Создание поста
post = Post(title='First Post', content='Hello!', author=user)
session.add(post)
session.commit()

# Запрос
user = session.query(User).filter_by(name='Alice').first()
print(user.posts)  # [<Post title='First Post'>]

Реляционные БД vs NoSQL

Реляционные БД:

  • Структурированные данные
  • Сложные связи
  • Нужна целостность
  • SQL запросы
  • Пример: PostgreSQL, MySQL

NoSQL (MongoDB, Redis):

  • Неструктурированные данные
  • Гибкая схема
  • Горизонтальная масштабируемость
  • JSON/документы
# Реляционная БД
users = [{'id': 1, 'name': 'Alice'}, ...]
posts = [{'id': 1, 'user_id': 1, 'title': '...'}, ...]

# NoSQL (MongoDB)
# Данные могут быть вложенными
user = {
    'id': 1,
    'name': 'Alice',
    'posts': [
        {'id': 1, 'title': 'Post 1'},
        {'id': 2, 'title': 'Post 2'}
    ]
}

Выводы

Реляционные БД нужны для:

  • Надёжного хранения структурированных данных
  • Обеспечения целостности через ограничения и связи
  • Эффективных запросов через индексы и оптимизацию
  • Многопользовательского доступа с транзакциями
  • Долговечности данных при сбоях

Реляционные БД — это стандарт для большинства бизнес-приложений. Они мощные, проверенные и обеспечивают надёжность, которая критична для бизнеса.