Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Опыт работы с различными базами данных
Я работал с различными типами баз данных, и каждая имеет свои сильные стороны. Расскажу о моём опыте и подходе к выбору БД для разных задач.
PostgreSQL — основная БД для большинства проектов
Это мой выбор по умолчанию для 80% приложений. Почему:
- ACID гарантии — надёжные транзакции
- JSON/JSONB — гибкость без потери типизации
- Full-text search — встроенный поиск
- Отличные индексы — B-tree, GiST, GIN
- Зрелость — 25+ лет разработки
// Пример работы с PostgreSQL в Node.js
const { Pool } = require('pg');
const pool = new Pool({
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
host: process.env.DB_HOST,
port: 5432,
database: process.env.DB_NAME
});
// Параметризованные запросы (защита от SQL injection)
const getUserById = async (userId) => {
const result = await pool.query(
'SELECT id, email, role FROM users WHERE id = $1',
[userId]
);
return result.rows[0];
};
// Транзакции для atomicity
const transferMoney = async (fromUserId, toUserId, amount) => {
const client = await pool.connect();
try {
await client.query('BEGIN');
// Блокируем строки для безопасности
await client.query(
'UPDATE accounts SET balance = balance - $1 WHERE user_id = $2 FOR UPDATE',
[amount, fromUserId]
);
await client.query(
'UPDATE accounts SET balance = balance + $1 WHERE user_id = $2',
[amount, toUserId]
);
await client.query('COMMIT');
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
};
// JSONB для гибкости
const storeMetadata = async (userId, metadata) => {
await pool.query(
'UPDATE users SET metadata = $1 WHERE id = $2',
[JSON.stringify(metadata), userId]
);
};
// Full-text search
const searchUsers = async (query) => {
const result = await pool.query(`
SELECT id, email, name
FROM users
WHERE to_tsvector('english', name || ' ' || email) @@ plainto_tsquery('english', $1)
LIMIT 10
`, [query]);
return result.rows;
};
// Миграции с Goose (raw SQL)
// 0001_create_users.sql
/*
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
*/
MongoDB — когда структура данных не определена
Использую для:
- Быстрого прототипирования — schema может меняться
- Документоориентированных данных — logs, events, analytics
- Высокого масштабирования — горизонтальное шардирование
const { MongoClient } = require('mongodb');
const client = new MongoClient(process.env.MONGO_URI);
const db = client.db('myapp');
// Гибкая схема
const storeEvent = async (event) => {
const result = await db.collection('events').insertOne({
type: event.type,
userId: event.userId,
data: event.data, // Может содержать что угодно
timestamp: new Date(),
metadata: {
ip: event.ip,
userAgent: event.userAgent
}
});
return result.insertedId;
};
// Aggregation pipeline для аналитики
const getUserAnalytics = async (userId) => {
const pipeline = [
{ $match: { userId: new ObjectId(userId) } },
{ $group: {
_id: '$type',
count: { $sum: 1 },
lastEvent: { $max: '$timestamp' }
} },
{ $sort: { count: -1 } }
];
return await db.collection('events').aggregate(pipeline).toArray();
};
// Transaction (MongoDB 4.0+)
const session = client.startSession();
await session.withTransaction(async () => {
await db.collection('orders').insertOne({ ...order }, { session });
await db.collection('inventory').updateOne({}, { ...update }, { session });
});
Redis — кеширование и real-time данные
Использую для:
- Сессии — быстрый доступ
- Кеш — уменьшение нагрузки на БД
- Real-time features — WebSocket, pub/sub
- Rate limiting — счётчик запросов
- Background jobs — через Bull
const redis = require('redis');
const client = redis.createClient();
// Сессии
const storeSession = async (sessionId, data) => {
await client.setEx(
`session:${sessionId}`,
3600, // 1 час TTL
JSON.stringify(data)
);
};
// Кеширование результатов дорогих операций
const getCachedUser = async (userId) => {
const cacheKey = `user:${userId}`;
// Проверяем кеш
let user = await client.get(cacheKey);
if (user) {
return JSON.parse(user);
}
// Если нет в кеше — достаём из БД
user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
// Сохраняем в кеш на 5 минут
await client.setEx(cacheKey, 300, JSON.stringify(user));
return user;
};
// Rate limiting
const checkRateLimit = async (userId, limit = 100, window = 3600) => {
const key = `rate:${userId}`;
const current = await client.incr(key);
if (current === 1) {
await client.expire(key, window);
}
if (current > limit) {
throw new Error('Rate limit exceeded');
}
};
// Pub/Sub для real-time notifications
const subscriber = redis.createClient();
await subscriber.subscribe('notifications', (message) => {
console.log('Notification:', message);
});
// Publisher
const notifyUser = async (userId, message) => {
await client.publish('notifications', JSON.stringify({
userId,
message,
timestamp: new Date()
}));
};
// Background jobs с Bull
const Queue = require('bull');
const emailQueue = new Queue('emails', process.env.REDIS_URL);
emailQueue.process(async (job) => {
await sendEmail(job.data.email, job.data.subject);
});
const sendEmailAsync = async (email, subject) => {
await emailQueue.add(
{ email, subject },
{ attempts: 3, backoff: { type: 'exponential', delay: 2000 } }
);
};
Elasticsearch — полнотекстовый поиск и аналитика
Использую для:
- Мощного поиска — лучше чем PostgreSQL full-text
- Логирования — ELK стек
- Аналитики — агрегация больших объёмов данных
const { Client } = require('@elastic/elasticsearch');
const client = new Client({ node: 'http://localhost:9200' });
// Индексирование
const indexProduct = async (product) => {
await client.index({
index: 'products',
id: product.id,
body: {
name: product.name,
description: product.description,
price: product.price,
category: product.category
}
});
};
// Сложный поиск
const searchProducts = async (query, filters) => {
const result = await client.search({
index: 'products',
body: {
query: {
bool: {
must: [
{ multi_match: {
query,
fields: ['name^2', 'description']
} }
],
filter: [
{ range: { price: { gte: filters.minPrice, lte: filters.maxPrice } } },
{ term: { category: filters.category } }
]
}
}
}
});
return result.hits.hits;
};
Выбор БД для конкретного проекта
Задача | БД | Причина
------------------------------|--------------------|-----------
Ecommerce (заказы, товары) | PostgreSQL | ACID, надёжность
Реал-тайм чат, уведомления | Redis + PostgreSQL | Redis для скорости
Мобильное приложение | MongoDB | гибкость, offline-first
Аналитика и логирование | Elasticsearch | масштабирование
Кеширование | Redis | скорость
Полнотекстовый поиск | Elasticsearch | мощный поиск
Микросервисная архитектура | PostgreSQL + Redis | независимость
IoT данные (временные ряды) | TimescaleDB | оптимизация
Лучшие практики
// 1. Connection pooling
const pool = new Pool({ max: 20 });
// 2. Prepared statements (защита от SQL injection)
const query = 'SELECT * FROM users WHERE id = $1'; // $1 вместо конкатенации
// 3. Индексы на часто используемые поля
// CREATE INDEX idx_users_email ON users(email);
// 4. Мониторинг медленных запросов
// Запросы > 1 сек логируем
// 5. Кешируем результаты в Redis
const getData = async (key) => {
let data = await redis.get(key);
if (data) return JSON.parse(data);
data = await db.query(...);
await redis.setEx(key, 3600, JSON.stringify(data));
return data;
};
// 6. Транзакции для критичных операций
await db.query('BEGIN');
try {
// несколько операций
await db.query('COMMIT');
} catch (error) {
await db.query('ROLLBACK');
}
Мой подход: PostgreSQL для основного приложения + Redis для кеша и real-time + специализированные БД где необходимо (Elasticsearch для поиска, MongoDB для специфичных случаев).