Files
knowledge-base/DATABASES.md
Stanislav Hubacek c6fa0bff6a commit
2026-06-11 15:27:28 +02:00

395 lines
17 KiB
Markdown

# 🗄️ Databázová architektura
## Klasifikace databází
### Relační (SQL)
| DB | Licence | Use case |
|----|---------|----------|
| PostgreSQL | Open source | Univerzální, geospatial, analytika |
| MySQL | Open source | Web, LAMP stack |
| MariaDB | Open source | MySQL kompatibilní |
| Microsoft SQL Server | Proprietary | Enterprise .NET |
| Oracle DB | Proprietary | Enterprise |
| Amazon Aurora | Managed | MySQL/PostgreSQL kompatibilní |
### NoSQL
| Typ | DB | Use case |
|-----|----|----------|
| Document | MongoDB, Couchbase | JSON data, flexibilní schema |
| Key-Value | Redis, DynamoDB | Cache, session store, real-time |
| Wide-column | Cassandra, ScyllaDB | Time-series, IoT, velká data |
| Graph | Neo4j, Dgraph | Vztahy, doporučení, social grafy |
## Transaction isolation levels
| Úroveň | Dirty Read | Non-repeatable Read | Phantom Read | Serialization Anomaly |
|--------|-----------|---------------------|-------------|----------------------|
| **Read Uncommitted** | Ano (možné) | Ano | Ano | Ano |
| **Read Committed** | Ne (prevence) | Ano | Ano | Ano |
| **Repeatable Read** | Ne | Ne | Ano (PostgreSQL: Ne) | Ano |
| **Serializable** | Ne | Ne | Ne | Ne |
**Anomálie**:
- **Dirty Read** — čtení dat z necommitnuté transakce (data mohou být rollbacknuta)
- **Non-repeatable Read** — stejný dotaz vrátí jiná data (jiná transakce mezitím updatovala řádek)
- **Phantom Read** — stejný dotaz vrátí nové řádky (jiná transakce insertla data splňující podmínku)
- **Serialization Anomaly** — výsledek transakcí není ekvivalentní žádnému sériovému pořadí
### PostgreSQL specific
- **Read Uncommitted** se chová jako **Read Committed** (není implementováno)
- **Repeatable Read** v PG je **Snapshot Isolation** — zabraňuje i phantom reads
- **Serializable** v PG používá Serializable Snapshot Isolation (SSI) — detekce sériových konfliktů
## PostgreSQL detail
### MVCC (Multi-Version Concurrency Control)
- Každá transakce vidí snapshot dat (transaction snapshot) z okamžiku startu
- Staré verze řádků (tuple) zůstávají v tabulce, označené jako `xmax` / `xmin`
- INSERT vytvoří nový tuple s `xmin = current_xid`
- DELETE označí tuple `xmax = current_xid` (nezmizí hned)
- UPDATE = DELETE old + INSERT new
- VACUUM fyzicky maže tuple starší než nejstarší aktivní snapshot
### VACUUM a autovacuum
| Parametr | Popis | Výchozí |
|----------|-------|---------|
| `autovacuum_vacuum_threshold` | Min. mrtvých řádků pro spuštění | 50 |
| `autovacuum_vacuum_scale_factor` | % z tabulky jako threshold | 0.2 (20 %) |
| `autovacuum_analyze_threshold` | Min. změněných řádků pro ANALYZE | 50 |
| `autovacuum_vacuum_cost_limit` | Limituje I/O vacuum (prevence zátěže) | 200 |
| `autovacuum_naptime` | Interval mezi kontrolami | 1 min |
| `deadlock_timeout` | Detekce deadlocků | 1 s |
**Příznaky nedostatečného vacuum**:
- Růst tabulky (bloat) — staré tuple zabírají místo
- Zhoršení výkonu index scanů (VISIBLE MAP není aktuální)
- XID wraparound hazard — emergency vacuum (může zastavit DB)
### WAL archiving a PITR
```conf
# postgresql.conf
wal_level = replica # nebo logical
archive_mode = on
archive_command = 'aws s3 cp %p s3://backups/pg-wal/%f'
```
- **WAL** (Write-Ahead Log) — append-only log všech změn
- **WAL archiving** — kontinuální záloha WAL segmentů (16 MB)
- **PITR** (Point-In-Time Recovery) — obnova k libovolnému okamžiku
1. Restore base backup (pg_basebackup)
2. Replay WAL archivů až k cílovému času
3. `recovery_target_time = '2026-06-03 10:30:00 UTC'`
### Replication slots
- **Physical replication slot** — zaručuje, že WAL není smazán masterem, dokud ho replica nespotřebuje
- **Logical replication slot** — pro logickou replikaci (selectivní tabulky, transformace dat)
- **Riziko**: pokud replica spadne a slot není aktivní, WAL naroste na disku (disk full)
- Monitoring: `pg_replication_slots`, `pg_stat_replication`
## Replikace
| Typ | Popis | Latence |
|-----|-------|---------|
| Synchronní | Zápis potvrzen až po replikaci na všechny nod | Vysoká, ale konzistentní |
| Asynchronní | Zápis potvrzen ihned, replikace na pozadí | Nízká, možný data loss |
| Semi-synchronní | Potvrzení od majority nodů | Kompromis |
### Topologie
- **Leader-Follower** (Master-Slave) — čtení z replic
- **Leader-Leader** (Multi-master) — zápis na více nodů
- **Quorum-based** — R + W > N (Cassandra, DynamoDB)
## Index types
| Typ | Algoritmus | Use case | Operace | Poznámka |
|-----|-----------|----------|---------|----------|
| **B-tree** | Balanced tree | Většina dotazů — =, <, >, BETWEEN, IN, LIKE (prefix) | Rychlé vyhledávání, řazení | Výchozí v PostgreSQL, MySQL |
| **Hash** | Hash table | Pouze = (equality) | Rychlé lookup | Malá velikost, nelze range dotazy |
| **GiST** | Generalized Search Tree | Full-text, geometrie, intervaly, IP rozsahy | Rychlé: overlaps, contains, distance | GIST pro geometrii (PostGIS), full-text |
| **GIN** (Generalized Inverted Index) | Inverted index | Pole, JSONB, full-text search | contains (@>), overlaps (&&) | Pomalý build, rychlé čtení |
| **BRIN** (Block Range Index) | Min/Max per block range | Velké tabulky, data v pořadí (time-series) | Range dotazy na korelovaná data | Extrémně malý (tisíckrát menší než B-tree) |
| **SP-GiST** | Space-partitioned GiST | Quad-tree, KD-tree, radix tree | Partitioned search | Geografické clustery, síťová data |
## Index selection guide
| Query pattern | Doporučený index | Příklad |
|--------------|-----------------|---------|
| `WHERE user_id = 123` | B-tree na `user_id` | Uživatelský lookup |
| `WHERE status = 'active' AND created_at > '2026-01-01'` | Composite B-tree na `(status, created_at)` | Filtrace + range |
| `WHERE data @> '{"key": "value"}'` | GIN na JSONB sloupec | JSONB dotazy |
| `WHERE tags && ARRAY['urgent']` | GIN na pole | Tagy |
| `WHERE position <@> POINT(50, 14) < 1000` | GiST na geometry | Lokalitní dotazy |
| `WHERE event_time BETWEEN '2026-06-01' AND '2026-06-02'` | BRIN na `event_time` | Time-series, logy |
| `WHERE email = 'user@example.com'` | Hash na `email` | Equality only |
## Query execution
### Seq scan vs Index scan vs Bitmap scan
| Typ | Popis | Kdy se používá |
|-----|-------|---------------|
| **Seq Scan** | Prochází všechny řádky tabulky | Velká část tabulky (>10 %), malá tabulka, žádný vhodný index |
| **Index Scan** | Hledá v indexu, pak náhodný přístup k heap | Malá podmnožina dat (<5 %), selektivní dotazy |
| **Index Only Scan** | Načítá data pouze z indexu (ne z heap) | Všechny potřebné sloupce jsou v indexu (covering index) |
| **Bitmap Scan** | Kombinace více indexů → bitmapa → heap access | AND/OR podmínky na více indexovaných sloupcích |
| **Bitmap Heap Scan** | Načítá řádky z bitmapy (srovnané) | AND/OR kombinace, ~5-20 % tabulky |
### EXPLAIN ANALYZE
```sql
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT * FROM orders WHERE user_id = 456 AND created_at > '2026-01-01';
-- Výstup:
-- Index Scan using idx_orders_user_created on orders
-- Index Cond: ((user_id = 456) AND (created_at > '2026-01-01'::date))
-- Buffers: shared hit=3
-- Planning Time: 0.12 ms
-- Execution Time: 0.34 ms
```
Klíčové metriky: `Execution Time`, `Planning Time`, `Buffers` (hit/read/dirtied), `Rows Removed by Filter`, `Actual Time` (first...last)
## Sharding
Distribuce dat napříč uzly podle shard klíče.
```
┌─────────┐
│ Proxy │
│ Router │
└────┬────┘
┌──────────┼──────────┐
┌────▼───┐ ┌───▼────┐ ┌───▼────┐
│Shard A │ │Shard B │ │Shard C │
│ 0-100 │ │101-200 │ │201-300 │
└────────┘ └────────┘ └────────┘
```
### Hash-based sharding
```
shard_id = hash(shard_key) % number_of_shards
```
### Range-based sharding
- Data rozdělena podle rozsahu hodnot (např. uživatelé A-M, N-Z)
- Může vést k nerovnoměrnému rozdělení (hot spots)
### Consistent hashing
```
Hash ring:
0 ─── shard A ─── hash(key1)
90 ─── shard B ─── hash(key2)
180 ─── shard C ─── hash(key3)
270 ─── shard D ─── hash(key4)
```
- Minimalizuje přeuspořádání přidáním/odebráním nodu (pouze sousední shard)
- **Virtual nodes** (vnodes) — každý fyzický nod má více virtuálních bodů na ring (lepší distribuce)
- **Koordinační služba**: Cassandra (vnodes), Riak (vnodes), DynamoDB (Consistent Hashing)
### Rebalancing
- **Ruční** — zastavit zápisy, přerozdělit data, restartovat
- **Automatické** — incremental migration (Cassandra vnodes)
- **Proxy-based** — Vitess (shard splitting), Citus (shard rebalancing)
### Routing approaches
- **Proxy-based** — aplikace jde na proxy, ta routuje (Vitess, ProxySQL)
- **Client-side** — aplikace ví, na který shard jít
- **DNS-based** — každý shard má vlastní endpoint
## CAP teorém
V distribuovaném systému lze mít pouze 2 ze 3:
- **C**onsistency — všichni vidí stejná data
- **A**vailability — každý request dostane odpověď
- **P**artition tolerance — systém funguje i přes výpadek komunikace
V praxi: P je vždy vyžadováno, volíme mezi CP (konzistence) a AP (dostupnost).
### PACELC rozšíření
PACELC rozšiřuje CAP o chování za normálních podmínek (bez partition):
- **P**artition → **A**vailability vs **C**onsistency
- **E**lse (bez partition) → **L**atency vs **C**onsistency
| DB | Partition volba | Else volba |
|----|----------------|------------|
| Cassandra | AP (dostupnost) | LC (nízká latence, eventual consistency) |
| DynamoDB (default) | AP | LC |
| MongoDB | CP (primární) | LC |
| PostgreSQL (single) | CP | CC |
| CockroachDB | CP | CC |
### Quorum detail
- **R** (read quorum) + **W** (write quorum) > **N** (replication factor)
- Typické: N=3, R=2, W=2 (toleruje 1 node down)
- **Sloppy quorum** — při nedostupnosti nodu, data dočasně uložena na jiném nodu (nastolit konzistenci po obnově)
- **Hinted handoff** — dočasný zápis na jiný node s hintem, při obnově se data přenesou
## Caching
| Vrstva | Nástroj | Use case |
|--------|---------|----------|
| Application cache | Redis, Memcached | Session, API response cache |
| Database cache | Built-in | Query cache, buffer pool |
| CDN cache | CloudFront, Fastly | Static assets, API responses |
| HTTP cache | Varnish, nginx | Reverse proxy cache, ESI |
### Cache strategie
| Strategie | Popis | Use case |
|-----------|-------|----------|
| **Cache-aside** | Aplikace načte z cache, při miss jde do DB a naplní cache | Obecná |
| **Read-through** | Cache sama načte z DB při miss | Jednoduché lookupy |
| **Write-through** | Zápis jde do cache i DB zároveň | Konzistence |
| **Write-behind** | Zápis do cache okamžitě, do DB asynchronně | Propustnost |
| **Cache-aside (lazy loading)** | TTL + invalidace | Nejčastější |
### Redis detail
**Data structures**:
| Struktura | Popis | Use case |
|-----------|-------|----------|
| **String** | Binární string (max 512 MB) | Cache hodnoty, session tokeny, counters |
| **Hash** | Map field-value | Uživatelský profil, objekt v cache |
| **List** | Linked list (push/pop na oba konce) | Queue (RPUSH/LPOP), log stream |
| **Set** | Unikátní hodnoty (unordered) | Tags, deduplikace, memberships |
| **Sorted Set** | Unikátní + score (řazení) | Leaderboardy, rate limiting, timeouts |
| **Bitmap** | Bitové pole | Feature flagy, daily active users |
| **HyperLogLog** | Approximate cardinality (12 KB = 2^64) | Unikátní návštěvníci (error < 1%) |
| **Stream** | Append-only log (Kafka-like) | Event store, messaging |
**Eviction policies**:
| Policy | Popis | Use case |
|--------|-------|----------|
| **noeviction** | Chyba při zápisu když je plno | Transakční data, neztrácet |
| **allkeys-lru** | LRU na všechny klíče | Obecná cache, standard |
| **allkeys-lfu** | LFU na všechny klíče | Často přistupovaná data |
| **volatile-lru** | LRU na klíče s TTL | Cache s expirací |
| **volatile-ttl** | Nejblíž k expiraci | Krátkodobá data |
| **allkeys-random** | Náhodný | Testování |
**Redis Cluster vs Sentinel**:
| Vlastnost | Redis Sentinel | Redis Cluster |
|-----------|---------------|---------------|
| **Škálování** | Read replicas (master + replica) | Data sharding (16384 hash slotů) |
| **Auto-failover** | Ano (Sentinel) | Ano (gossip-based) |
| **Multi-key ops** | Ano (transactiony na masteru) | Omezené (stejný hash slot) |
| **Client komunikace** | Přes Sentinel (deprecated) | Cluster nodes redirect (MOVED/ASK) |
| **Minimální uzly** | Master + Replica + 3 Sentinel | 3 masters (každý s replikou) |
| **Use case** | Vysoká dostupnost, single shard | Multi-shard, horizontální škálování |
### Connection pooling
| Pooler | DB | Typ | Protokol |
|--------|-----|-----|----------|
| **PgBouncer** | PostgreSQL | Proxy (transaction/session) | PostgreSQL wire |
| **RDS Proxy** | PostgreSQL, MySQL | Managed proxy | AWS |
| **ProxySQL** | MySQL | Proxy (advanced routing) | MySQL wire |
| **Odyssey** | PostgreSQL | Proxy (multithreaded) | PostgreSQL wire |
| **pgpool-II** | PostgreSQL | Proxy (replication, load balancing) | PostgreSQL wire |
**PgBouncer režimy**:
- **Session pooling** — spojení drženo po celou dobu session (aplikace) → overhead
- **Transaction pooling** — spojení vráceno po dokončení transakce → efektivnější (vyžaduje bezstavovost)
## Migrace dat
### Schéma migrace (PostgreSQL / MySQL)
```
V1__initial_schema.sql
V2__add_users_table.sql
V3__add_email_index.sql
V4__add_orders_table.sql
```
### Zero-downtime migrace
1. **Expand** — přidání nového sloupce/tabulky (aplikace toleruje oba stavy)
2. **Migrate** — backfill dat, update aplikace na nové schema
3. **Contract** — odstranění starého sloupce/tabulky
### Nástroje detail
| Nástroj | Jazyk | Strategie | Zero-downtime | Rollback |
|---------|-------|-----------|--------------|----------|
| **Flyway** | Java (multi-lang CLI) | Versioned SQL | Omezeně (jen additive) | `undo` (limited, enterprise) |
| **Liquibase** | Java (multi-lang CLI) | Changesets (XML/YAML/JSON/SQL) | Ano (changeset design) | `rollback <count>` |
| **Alembic** | Python | Auto-generation, versioned | Ano (branching) | `downgrade` |
| **Prisma Migrate** | TypeScript | Declarative schema → diff | Ano (shadow DB) | `migrate diff` |
| **gh-ost** | Go | Triggerless online DDL (MySQL) | Ano (binlog stream) | Ne (progresivní) |
| **pgroll** | Go | Online schema migrace (PG) | Ano (views, multiple versions) | Ano (okamžitý) |
## Data consistency patterns
| Pattern | Popis | Příklad |
|---------|-------|---------|
| **Strong consistency** | Po zápisu každý read vidí nejnovější data | Single DB, Raft, Spanner |
| **Eventual consistency** | Po zápisu se data časem propagují | DNS, DynamoDB (default), Cassandra |
| **Read-after-write** | Autor svůj zápis vždy vidí (ostatní eventual) | Sociální sítě, komentáře |
| **Causal consistency** | Kauzálně závislé operace viděny ve správném pořadí | COPS, Orbe, MongoDB (causal clusters) |
| **Monotonic reads** | Nevidíte starší data po tom, co jste viděli novější | Cassandra (MONOTONIC_READ consistency) |
| **Monotonic writes** | Zápisy od jednoho clienta v pořadí | Queue-based, single leader |
## Storage engines — přehled
### B-Tree vs LSM-Tree
| Vlastnost | B-Tree | LSM-Tree |
|-----------|--------|----------|
| Zápis | In-place update (náhodný I/O) | Append-only (sekvenční I/O) |
| Čtení | Rychlé (přímo v page) | Pomalejší (merge z více SSTable) |
| Kompaktnost | Horší (page fragmentation) | Lepší (kompaktní SSTable) |
| Write amplification | Nižší | Vyšší (kompakce) |
| Read amplification | Nižší | Vyšší (bloom filtry pomáhají) |
| Typické DB | PostgreSQL, MySQL (InnoDB) | Cassandra, RocksDB, LevelDB |
### Write-Ahead Log (WAL)
- Append-only log pro crash recovery
- Každá změna se zapíše do WAL před aplikací na data page
- Checkpoint = bod, od kterého je WAL při recovery potřeba
### MVCC (Multi-Version Concurrency Control)
- Každá transakce vidí snapshot dat v okamžiku startu
- Staré verze řádků zůstávají v tabulce (vacuum/GC)
- Izolační úrovně: Read Committed, Repeatable Read, Serializable
## Best practices
- **Connection pooling** — PgBouncer, RDS Proxy, ProxySQL
- **Indexování podle query patternů** — nemít zbytečné indexy
- **Read replicas** pro reporting a analytiku
- **Backup & recovery** — point-in-time recovery (PITR), pravidelné testy
- **Query monitoring** — slow query log, pg_stat_statements, performance_schema
- **Encryption at rest & in transit**
- **Migrace v CI/CD** — součást pipeline, ne manuálně
## Zdroje
Odkazy, knihy a standardy: [sources/databases/sources.md](sources/databases/sources.md)