✅ Good
Вступ до баз даних¶
База даних — організоване сховище для зберігання, керування та отримання даних. Замість тисяч файлів — структурована система з швидким пошуком та надійністю.
Чому це важливо для UMTC?
Всі сервіси UMTC використовують бази даних: Matrix Synapse зберігає повідомлення в PostgreSQL, Wiki використовує SQLite для пошуку, а моніторинг — для метрик.
Навіщо потрібна база даних?¶
flowchart LR
subgraph without["❌ Без БД"]
FILES["📁 JSON файли"]
SLOW["Повільний пошук O(n)"]
CONFLICT["Колізії записів"]
LOSS["Втрата даних"]
end
subgraph with["✅ З базою даних"]
DB["🗄️ PostgreSQL"]
INDEX["Швидкий пошук O(log n)"]
ACID["ACID транзакції"]
BACKUP["Резервне копіювання"]
end
FILES --> SLOW --> CONFLICT --> LOSS
DB --> INDEX --> ACID --> BACKUP
style without fill:#fee2e2
style with fill:#d1fae5SQL vs NoSQL¶
SQL (реляційні бази даних)¶
Дані організовані в таблиці з рядками та колонками. Є чітка схема (структура даних).
flowchart TB
subgraph users["Таблиця users"]
U["id | name | email | created_at"]
end
subgraph orders["Таблиця orders"]
O["id | user_id | product | price"]
end
users -->|"JOIN<br/>user_id"| orders
style users fill:#dbeafe
style orders fill:#d1fae5| id | name | created_at | |
|---|---|---|---|
| 1 | Олександр | alex@example.com | 2026-01-15 |
| 2 | Марія | maria@example.com | 2026-01-16 |
Приклади SQL баз:
- PostgreSQL — найпотужніша, рекомендована
- MySQL/MariaDB — популярна для веб
- SQLite — вбудована, для простих застосунків
NoSQL (нереляційні бази даних)¶
Гнучка структура, без жорсткої схеми.
{
"_id": "user_001",
"name": "Олександр",
"email": "alex@example.com",
"orders": [
{ "product": "Laptop", "price": 25000 },
{ "product": "Mouse", "price": 500 }
],
"preferences": {
"theme": "dark",
"language": "uk"
}
}
Типи NoSQL:
| Тип | Опис | Приклад |
|---|---|---|
| Document | JSON-подібні документи | MongoDB |
| Key-Value | Простий ключ → значення | Redis |
| Column | Колонкове сховище | Cassandra |
| Graph | Зв'язки між даними | Neo4j |
Коли що використовувати?¶
mindmap
root((Вибір БД))
SQL PostgreSQL
Структуровані дані
Складні JOIN
ACID транзакції
Приклади
Користувачі
Замовлення
Фінанси
NoSQL MongoDB
Гнучка схема
Вкладені документи
Горизонтальне масштабування
Приклади
Логи
CMS контент
IoT дані
Redis
Кешування
Сесії
Черги
Rate limitingПорівняльна таблиця¶
| Критерій | PostgreSQL | MongoDB | Redis |
|---|---|---|---|
| Тип | SQL | Document | Key-Value |
| Схема | Строга | Гнучка | Немає |
| Транзакції | ACID | Базові | Обмежені |
| Масштабування | Вертикальне | Горизонтальне | Горизонтальне |
| Швидкість запису | Середня | Висока | Дуже висока |
| Складні запити | Відмінно | Добре | Немає |
| Зберігання | На диску | На диску | В RAM |
ACID принципи¶
ACID — гарантії для транзакцій в SQL базах даних:
flowchart TB
subgraph acid["ACID"]
A["🔹 Atomicity<br/>Все або нічого"]
C["🔹 Consistency<br/>Завжди коректний стан"]
I["🔹 Isolation<br/>Транзакції незалежні"]
D["🔹 Durability<br/>Дані не втрачаються"]
end
style acid fill:#dbeafe| Принцип | Опис | Приклад |
|---|---|---|
| Atomicity | Транзакція виконується повністю або не виконується | Переказ грошей: зняти + додати = атомарно |
| Consistency | База завжди в коректному стані | email унікальний — дублікати неможливі |
| Isolation | Паралельні транзакції не заважають | Два користувачі редагують різні рядки |
| Durability | Збережені дані не втрачаються | COMMIT пройшов — дані на диску |
Приклад транзакції¶
-- Переказ грошей: атомарна операція
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE user_id = 2;
-- Якщо все OK
COMMIT;
-- Якщо щось пішло не так
-- ROLLBACK;
ORM — що це?¶
ORM (Object-Relational Mapping) — бібліотека, що дозволяє працювати з базою через об'єкти замість SQL.
# Без ORM (чистий SQL)
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
row = cursor.fetchone()
user = {"id": row[0], "name": row[1], "email": row[2]}
# З ORM (SQLAlchemy)
user = session.query(User).filter(User.id == user_id).first()
print(user.name) # Працюємо як з об'єктом
Популярні ORM¶
| Мова | ORM |
|---|---|
| Python | SQLAlchemy, Django ORM |
| JavaScript | Prisma, Sequelize, TypeORM |
| Go | GORM, sqlx |
| Ruby | ActiveRecord |
| PHP | Eloquent (Laravel) |
Плюси і мінуси ORM¶
✓ Простіший код
✓ Захист від SQL injection
✓ Переносимість між БД
✓ Міграції схеми
✗ Складні запити важче оптимізувати
✗ N+1 проблема
✗ Додатковий шар абстракції
Індекси¶
Індекс — структура даних для швидкого пошуку. Як індекс в книзі — замість гортати всі сторінки, дивишся на потрібну літеру.
flowchart LR
subgraph without["❌ Без індексу O(n)"]
direction LR
R1["row 1"] --> R2["row 2"] --> R3["row 3"] --> RN["...1M рядків"]
end
subgraph with["✅ З індексом O(log n)"]
direction TB
M["[M]"]
D["[D]"]
S["[S]"]
A["[A] ← alex@..."]
M --> D
M --> S
D --> A
end
style without fill:#fee2e2
style with fill:#d1fae5-- Створення індексу
CREATE INDEX idx_users_email ON users(email);
Коли створювати індекси?
- Колонки в WHERE
- Колонки в JOIN
- Колонки в ORDER BY
- Унікальні значення (email, username)
Коли створювати індекси?¶
✓ Колонки в WHERE
✓ Колонки в JOIN
✓ Колонки в ORDER BY
✓ Унікальні значення (email, username)
✗ Не створювати на все поспіль
✗ Індекси займають місце
✗ Індекси уповільнюють INSERT/UPDATE
Практичний приклад: вибір БД¶
Веб-застосунок (типовий)¶
PostgreSQL — основна база
├── users (id, email, password_hash, created_at)
├── posts (id, user_id, content, created_at)
├── comments (id, post_id, user_id, content)
└── ...
Redis — кешування та сесії
├── session:abc123 → {user_id: 1, ...}
├── cache:posts:recent → [post1, post2, ...]
└── rate_limit:user:1 → 45
Docker Compose¶
services:
app:
image: myapp
depends_on:
- postgres
- redis
postgres:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: secret
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
Типові помилки¶
N+1 проблема¶
# Погано: N+1 запитів
users = User.query.all() # 1 запит
for user in users:
print(user.orders) # N запитів (по одному на user)
# Добре: 1-2 запити
users = User.query.options(
joinedload(User.orders)
).all()
Відсутність індексів¶
-- Повільно (Full Table Scan)
SELECT * FROM logs WHERE created_at > '2026-01-01';
-- Швидко (Index Scan)
CREATE INDEX idx_logs_created ON logs(created_at);
SELECT * FROM logs WHERE created_at > '2026-01-01';
SELECT *¶
-- Погано: тягнемо всі колонки
SELECT * FROM users;
-- Добре: тільки потрібні
SELECT id, name, email FROM users;
Пов'язані теми¶
- PostgreSQL основи — робота з PostgreSQL
- Бази даних (практика) — наша інфраструктура
- Docker Compose — запуск баз в контейнерах
- Synapse — приклад використання PostgreSQL
Шлях: services/databases/intro.md