> Расскажите про опыт работы с PostgreSQL (JavaScript)

Уровень: senior · Роль: backend · Язык: JavaScript · Категория: Технические вопросы

Компании: ЭНИРАН

Стек: Node.js, JavaScript, PostgreSQL

> Пример ответа

Короткий ответ

PostgreSQL - моя основная реляционная БД в production. Работаю с ней более 5 лет: проектирование схем, оптимизация запросов, миграции, настройка индексов, работа с JSONB, full-text search, оконные функции. В связке с Node.js использую pg (node-postgres) с пулом соединений, транзакциями и prepared statements. Сталкивался с replication, partitioning, vacuum tuning и мониторингом через pg_stat_statements.

Подробное объяснение

PostgreSQL - это объектно-реляционная СУБД с ACID compliance, MVCC, расширяемой системой типов и мощным планировщиком запросов. В production-проектах на Node.js я использую её для:

  • Схемы и миграции: проектирую нормализованные схемы с foreign keys, unique constraints, check constraints. Миграции через sqitch или flyway.
  • Индексы: B-tree, GIN для JSONB/массивов, GiST для full-text search, partial и covering indexes.
  • JSONB: хранение гибких структур с индексацией, обновление через jsonb_set, агрегация через jsonb_agg.
  • Full-text search: tsvector/tsquery с конфигурациями русского и английского языка, weighted search.
  • Оконные функции: ROW_NUMBER(), LAG(), SUM() OVER для пагинации, аналитики, дедупликации.
  • Транзакции: управление через BEGIN/COMMIT/ROLLBACK, savepoints, изоляция READ COMMITTED (по умолчанию) и SERIALIZABLE для конкурентных обновлений.
  • Connection pooling: pg-pool с настройкой max/min, idle timeout, statement timeout.
  • Мониторинг: pg_stat_statements для поиска медленных запросов, auto_explain для логирования планов.

На практике

В типичном Node.js-приложении:

  • pg как драйвер, knex или slonik для построения запросов (raw SQL для сложных случаев).
  • Пул соединений: new Pool({ max: 20, idleTimeoutMillis: 30000 }) - один пул на процесс, переиспользуется между запросами.
  • Миграции: каждая миграция - отдельный SQL-файл, запускается при старте приложения или через CLI.
  • Оптимизация: EXPLAIN ANALYZE для проблемных запросов, добавление индексов по фильтрам WHERE и JOIN, избегание N+1 через batch loading (DataLoader).
  • Обработка ошибок: retry logic для serialization failures, graceful shutdown с закрытием пула.

Пример кода

JAVASCRIPT
const { Pool } = require('pg');
const pool = new Pool({
host: process.env.DB_HOST,
database: 'mydb',
max: 20,
idleTimeoutMillis: 30000,
statement_timeout: 5000,
});
// Транзакция с savepoint
async function updateUserAndLog(userId, newEmail) {
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query('SAVEPOINT before_email_update');
const result = await client.query(
'UPDATE users SET email = $1 WHERE id = $2 RETURNING *',
[newEmail, userId]
);
if (result.rows.length === 0) {
await client.query('ROLLBACK TO SAVEPOINT before_email_update');
throw new Error('User not found');
}
await client.query(
'INSERT INTO audit_log (user_id, action) VALUES ($1, $2)',
[userId, 'email_updated']
);
await client.query('COMMIT');
return result.rows[0];
} catch (err) {
await client.query('ROLLBACK');
throw err;
} finally {
client.release();
}
}
// Полнотекстовый поиск с ранжированием
async function searchPosts(query) {
const result = await pool.query(`
SELECT
title,
ts_rank(search_vector, query) AS rank
FROM posts, plainto_tsquery('russian', $1) AS query
WHERE search_vector @@ query
ORDER BY rank DESC
LIMIT 20
`, [query]);
return result.rows;
}

Как отвечать на собеседовании

Начни с конкретных проектов: "В проекте X использовал PostgreSQL для хранения заказов с JSONB-полями, оптимизировал запросы через GIN-индексы". Покажи понимание trade-off: нормализация vs JSONB, B-tree vs GIN, READ COMMITTED vs SERIALIZABLE. Упомяни инструменты: pg_stat_statements, EXPLAIN ANALYZE, pgBadger. Если спросят про проблемы - расскажи про bloat, autovacuum tuning, lock contention.

Что проверяет интервьюер

  • Глубину практического опыта (не просто "знаю SQL", а конкретные кейсы).
  • Понимание внутренностей PostgreSQL: MVCC, vacuum, lock levels, планировщик.
  • Умение проектировать схемы и выбирать индексы под нагрузку.
  • Навыки работы с Node.js: пул соединений, транзакции, обработка ошибок.
  • Знание продвинутых фич: оконные функции, full-text search, JSONB.

Типичные ошибки

  • Использование SELECT * в production - лишние данные, нагрузка на I/O.
  • Отсутствие индексов на внешние ключи - блокировки при DELETE/UPDATE.
  • Игнорирование statement timeout - зависшие запросы блокируют пул.
  • Неправильная настройка пула: слишком много соединений (каждый процесс Node.js свой пул) или слишком мало (очереди).
  • Забывают про client.release() в catch/finally - утечка соединений.
  • Использование ORM без понимания генерируемого SQL - N+1, неэффективные запросы.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью