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

Какие знаешь критерии выбора БД?

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

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

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

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

Критерии выбора базы данных

Выбор БД — это одна из самых важных архитектурных решений. Не существует универсальной БД, нужно анализировать требования.

1. Структура данных

Структурированные данные (СУБД)

class User(Base):
    __tablename__ = "users"
    
    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False)
    name = Column(String(100))
    age = Column(Integer)
    created_at = Column(DateTime, default=datetime.utcnow)
    
    # Отношение к другой таблице
    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(255))
    content = Column(Text)

# PostgreSQL, MySQL, Oracle — идеальны для этого

Полуструктурированные данные (JSON, Document)

from mongomock import MongoClient  # или реальный MongoDB

db = MongoClient()["myapp"]
users_collection = db["users"]

# Гибкая схема
users_collection.insert_many([
    {"name": "Alice", "age": 25, "tags": ["python", "devops"]},
    {"name": "Bob", "email": "bob@example.com"},  # Нет age
    {"name": "Charlie", "meta": {"country": "US", "skills": ["C++"]}}  # Другая структура
])

# MongoDB отлично подходит для такого

Неструктурированные данные (текст, видео)

# Используем Object Storage (S3, MinIO) или File System
# БД хранит ссылки

class Document(Base):
    __tablename__ = "documents"
    
    id = Column(Integer, primary_key=True)
    filename = Column(String(255))
    file_path = Column(String(500))  # s3://bucket/docs/file.pdf
    mime_type = Column(String(50))
    size = Column(Integer)
    uploaded_at = Column(DateTime)

2. Масштабируемость

Вертикальная масштабируемость (scale-up)

  • PostgreSQL, MySQL: хороша (добавляем RAM, CPU на один сервер)
  • Ограничена: однопоточность, размер машины

Горизонтальная масштабируемость (scale-out)

# MongoDB с шардингом
from pymongo import MongoClient
from pymongo.errors import AutoReconnect

class MongoDBScaled:
    def __init__(self):
        # Шард 1
        self.shard1 = MongoClient("mongodb://shard1:27017")
        # Шард 2
        self.shard2 = MongoClient("mongodb://shard2:27017")
        # Шард 3
        self.shard3 = MongoClient("mongodb://shard3:27017")
    
    def get_shard(self, user_id: str):
        # Простой sharding по user_id
        shard_num = hash(user_id) % 3
        shards = [self.shard1, self.shard2, self.shard3]
        return shards[shard_num]

# Cassandra, DynamoDB — designed for horizontal scaling

3. Consistency vs Availability (CAP Theorem)

# CAP Theorem: Choose 2 of 3
# C - Consistency (точность данных)
# A - Availability (всегда доступна)
# P - Partition tolerance (стабильна при разрывах сети)

from enum import Enum

class DatabaseCategory(Enum):
    CA = "PostgreSQL, MySQL"  # Consistency + Availability (локальная сеть)
    AP = "MongoDB, Cassandra"  # Availability + Partition (Eventual Consistency)
    CP = "HBase, Bigtable"  # Consistency + Partition (жертвуем доступностью)

# PostgreSQL: ACID, immediate consistency, но нужна репликация
class BankAccount(Base):
    __tablename__ = "accounts"
    
    id = Column(Integer, primary_key=True)
    balance = Column(Numeric(10, 2))
    
    # Транзакция в PostgreSQL
    # ACID гарантирует: если переведём деньги, не потеряем ни копейки

# MongoDB: Eventual Consistency (данные консистентны со временем)
# Вставили в primary, может быть lag на replicas

4. Требования к транзакциям

# Нужны ACID транзакции?
class StrictTransaction:
    """Когда нужна 100% надёжность"""
    
    # PostgreSQL, Oracle, MySQL (InnoDB)
    # ACID гарантирует:
    # A - Atomicity (всё или ничего)
    # C - Consistency (корректное состояние)
    # I - Isolation (параллельные транзакции не мешают)
    # D - Durability (сохранено на диск)
    
    def transfer_money(from_account: int, to_account: int, amount: Decimal):
        with transaction:  # PostgreSQL ACID транзакция
            # Если что-то упадёт — всё откатится
            decrease_balance(from_account, amount)
            increase_balance(to_account, amount)

class EventualConsistency:
    """Когда можем мириться с временным несоответствием"""
    
    # MongoDB, Cassandra, DynamoDB
    # Event Sourcing вместо ACID
    
    async def record_event(event: Event):
        # Записываем событие
        await events_db.insert(event)
        
        # В фоне обновляем состояние
        # Может быть lag, но итоговое состояние корректно
        await update_state(event)

5. Скорость доступа

# In-Memory (очень быстро)
from redis import Redis

redis = Redis()

# SET/GET за микросекунды
redis.set("user:123:name", "Alice")  # ~10 мкс
name = redis.get("user:123:name")     # ~10 мкс

# Disk-Based (медленнее)
import sqlite3

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

# SELECT за миллисекунды
cursor.execute("SELECT name FROM users WHERE id = ?", (123,))  # ~1-10 мс
name = cursor.fetchone()

# Network-Based (ещё медленнее)
import requests

response = requests.get("https://api.example.com/users/123")  # ~100-500 мс

Выбор по скорости:

  • Кеш: Redis, Memcached (< 1 мс)
  • Основная БД: PostgreSQL, MySQL (1-10 мс)
  • Аналитика: ClickHouse (100-1000 мс)

6. Надёжность и Backup

# PostgreSQL с репликацией
# Primary ↔ Replica (synchronous replication)
# Гарантия: если primary упадёт, replica будет в точности как был

# MongoDB с Replica Set
# primary ← secondary1, secondary2
# Automatic failover: если primary упадёт, вторичная станет primary

# DynamoDB
# AWS managed, автоматический backup, cross-region replication
# Надёжность ≈ 99.99%

class BackupStrategy:
    def __init__(self):
        # Выбираем по RTO/RPO
        # RTO: Recovery Time Objective (сколько мин восстанавливаемся)
        # RPO: Recovery Point Objective (сколько данных теряем)
        
        self.postgres = {
            "rto": "5-10 мин",  # failover на replica
            "rpo": "0 сек",     # synchronous replication
        }
        
        self.mongodb = {
            "rto": "1-2 мин",  # автоmatic failover
            "rpo": "30 сек",   # asynchronous replication
        }

7. Производительность запросов

# OLTP (Online Transaction Processing) — много мелких операций
# PostgreSQL, MySQL, MongoDB — отлично

class OLTP:
    async def get_user(user_id: int):
        # SELECT * FROM users WHERE id = ?
        # Index Scan, < 1 мс
        return await db.users.get(user_id)
    
    async def update_balance(account_id: int, delta: Decimal):
        # UPDATE accounts SET balance = balance + ? WHERE id = ?
        # Fast, < 5 мс
        await db.accounts.update(account_id, {"balance": delta})

# OLAP (Online Analytical Processing) — большие аналитические запросы
# ClickHouse, Apache Druid, BigQuery — отлично

class OLAP:
    async def get_daily_revenue(start_date, end_date):
        # SELECT SUM(amount) FROM transactions 
        # WHERE date BETWEEN ? AND ? GROUP BY hour
        # ClickHouse: columnar storage, сжатие, 100x быстрее
        
        result = await clickhouse.query(
            "SELECT toStartOfHour(timestamp) as hour, SUM(amount) "
            "FROM transactions WHERE timestamp BETWEEN %(start)s AND %(end)s "
            "GROUP BY hour",
            {"start": start_date, "end": end_date}
        )
        return result

8. Матрица выбора БД

┌──────────────┬──────────┬─────────────┬─────────┬──────────┬──────────┐
│ БД           │ Структ.  │ Масштаб     │ ACID    │ Скорость │ Сложност │
├──────────────┼──────────┼─────────────┼─────────┼──────────┼──────────┤
│ PostgreSQL   │ ⭐⭐⭐⭐⭐ │ Вертик.     │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐⭐  │ ⭐⭐     |
│ MySQL        │ ⭐⭐⭐⭐⭐ │ Вертик.     │ ⭐⭐⭐⭐  │ ⭐⭐⭐⭐  │ ⭐⭐     |
│ MongoDB      │ ⭐⭐⭐⭐  │ Горизонт.   │ ⭐⭐⭐  │ ⭐⭐⭐⭐  │ ⭐⭐⭐   |
│ Redis        │ ⭐⭐     │ Горизонт.   │ ⭐⭐⭐  │ ⭐⭐⭐⭐⭐ │ ⭐⭐     |
│ Cassandra    │ ⭐⭐⭐   │ ⭐⭐⭐⭐⭐   │ ⭐⭐   │ ⭐⭐⭐⭐  │ ⭐⭐⭐⭐ |
│ ClickHouse   │ ⭐⭐⭐   │ Горизонт.   │ ⭐     │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐   |
│ ElasticSearch│ ⭐⭐⭐   │ Горизонт.   │ ⭐     │ ⭐⭐⭐⭐  │ ⭐⭐⭐   |
│ DynamoDB     │ ⭐⭐⭐   │ ⭐⭐⭐⭐⭐   │ ⭐⭐  │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐⭐ |
└──────────────┴──────────┴─────────────┴─────────┴──────────┴──────────┘

9. Практические примеры

# Стартап, <100k пользователей
class SmallApp:
    db = "PostgreSQL"
    cache = "Redis"
    # Простая архитектура, одного PostgreSQL достаточно

# Medium (100k-1M пользователей)
class MediumApp:
    primary_db = "PostgreSQL"
    read_replicas = ["PostgreSQL", "PostgreSQL"]  # масштабирование чтения
    cache = "Redis"
    search = "ElasticSearch"

# Large (1M+ пользователей)
class LargeApp:
    oltp = "MongoDB с шардингом"  # горизонтальное масштабирование
    olap = "ClickHouse"  # аналитика
    cache = "Redis Cluster"
    search = "ElasticSearch Cluster"
    realtime = "Kafka для event streaming"

# Финтех (требует максимальной надёжности)
class FinTechApp:
    primary = "PostgreSQL с synchronous replication"
    audit = "PostgreSQL (для жёсткой истории)"
    backup = "Dedicated backup сервер"
    disaster_recovery = "Cross-region PostgreSQL"

10. Антипаттерны

# ❌ Используешь MongoDB для структурированных данных, которые требуют ACID
# ✅ PostgreSQL лучше подходит

# ❌ Кешируешь всё в Redis без стратегии eviction
# ✅ Определи TTL и eviction policy

# ❌ Выбираешь ClickHouse для OLTP операций
# ✅ ClickHouse для аналитики, PostgreSQL для OLTP

# ❌ Игнорируешь репликацию и backup
# ✅ Настрой репликацию в день 1

Процесс выбора

  1. Определи требования: структура, объём, RPS, RTO/RPO
  2. Выбери категорию: OLTP, OLAP, KV-store, Search
  3. Оцени CAP: Consistency vs Availability vs Partition Tolerance
  4. Прототипируй: не выбирай на ощупь, тестируй
  5. Проверь операционность: есть ли опыт в команде, документация
  6. Планируй рост: как будешь масштабировать?

В большинстве случаев начинай с PostgreSQL — универсальна, надёжна, масштабируется.