Комментарии (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
Процесс выбора
- Определи требования: структура, объём, RPS, RTO/RPO
- Выбери категорию: OLTP, OLAP, KV-store, Search
- Оцени CAP: Consistency vs Availability vs Partition Tolerance
- Прототипируй: не выбирай на ощупь, тестируй
- Проверь операционность: есть ли опыт в команде, документация
- Планируй рост: как будешь масштабировать?
В большинстве случаев начинай с PostgreSQL — универсальна, надёжна, масштабируется.