PostgreSQL — самая популярная СУБД среди российских технологических компаний. Если в вашей команде используется Postgres, стоит проверять не только универсальный SQL, но и знание специфики этой базы данных.
Что отличает PostgreSQL-специфичные вопросы
Существует два уровня SQL-знаний:
- Стандартный SQL — работает в любой СУБД
- PostgreSQL-специфичный — функции, типы данных и поведение, уникальные для Postgres
При найме важно разделять: вы ищете человека, который знает стандартный SQL, или того, кто работал именно с PostgreSQL?
Тема 1: Типы данных PostgreSQL
-- PostgreSQL поддерживает типы, которых нет в других СУБД
-- JSONB, UUID, ARRAY, tsrange и другие
-- Задача: найдите пользователей, у которых в настройках (JSONB)
-- включены email-уведомления
SELECT id, name
FROM users
WHERE settings ->> 'email_notifications' = 'true';
-- Задача: найдите все теги, которые встречаются в массиве тегов статей
SELECT DISTINCT unnest(tags) AS tag
FROM articles
ORDER BY tag;
Что проверяем: знакомство с JSONB-операторами (->, ->>), работа с массивами через unnest.
Тема 2: EXPLAIN и план выполнения
-- Попросите кандидата прочитать вывод EXPLAIN ANALYZE
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id) AS order_count
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.created_at > '2026-01-01'
GROUP BY u.id, u.name
HAVING COUNT(o.id) > 5;
Что ищем в объяснении кандидата:
- Понимает ли он
Seq ScanvsIndex Scan? - Что значат
cost=0.00..1234.56? - Почему появился
Hash JoinвместоNested Loop? - Что такое
rows=1000 width=32и зачем?
Хороший ответ: кандидат смотрит на самые дорогие узлы (сортирует по actual time), проверяет, есть ли индексы на полях JOIN и WHERE, обращает внимание на расхождение между rows (оценка планировщика) и actual rows.
Тема 3: DISTINCT ON — специфика PostgreSQL
-- DISTINCT ON есть только в PostgreSQL
-- Задача: для каждого пользователя найдите самый последний заказ
-- PostgreSQL-способ (лаконично):
SELECT DISTINCT ON (user_id) *
FROM orders
ORDER BY user_id, created_at DESC;
-- Стандартный SQL через ROW_NUMBER:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn
FROM orders
) t WHERE rn = 1;
Senior-разработчик должен знать оба способа и объяснить разницу в производительности.
Тема 4: Работа с датами и временными зонами
-- PostgreSQL строго работает с timezone — частый источник ошибок
-- Задача: выведите количество регистраций по часам (по московскому времени)
SELECT
EXTRACT(HOUR FROM registered_at AT TIME ZONE 'Europe/Moscow') AS hour_msk,
COUNT(*) AS registrations
FROM users
GROUP BY 1
ORDER BY 1;
-- Ловушка: если registered_at хранится в UTC (как обычно),
-- без AT TIME ZONE результат будет некорректным
Что проверяем: понимание UTC vs localtime, оператор AT TIME ZONE, функции EXTRACT и DATE_TRUNC.
Тема 5: Индексы в PostgreSQL
Спросите кандидата: «Когда вы бы создали partial index вместо обычного?»
-- Partial index: индексируем только активные заказы
-- Если 95% заказов неактивны, индекс будет маленьким и быстрым
CREATE INDEX idx_orders_active ON orders (user_id)
WHERE status = 'active';
-- Functional index: индексируем результат функции
CREATE INDEX idx_users_email_lower ON users (LOWER(email));
-- Позволяет быстро искать: WHERE LOWER(email) = 'user@example.com'
Что проверяем: знает ли кандидат типы индексов (B-tree, Hash, GIN, GiST)?
Тема 6: Специфичные функции
-- COALESCE — заменить NULL на значение
SELECT COALESCE(middle_name, '') AS middle_name FROM persons;
-- NULLIF — вернуть NULL при совпадении значений (защита от деления на ноль)
SELECT amount / NULLIF(quantity, 0) AS unit_price FROM items;
-- GENERATE_SERIES — генерация последовательности (незаменимо для отчётов)
SELECT generate_series::DATE AS report_date
FROM generate_series('2026-01-01'::DATE, '2026-01-31'::DATE, '1 day') generate_series;
-- Это позволяет заполнять "дыры" в данных:
WITH dates AS (
SELECT generate_series::DATE AS dt
FROM generate_series('2026-01-01', '2026-01-31', '1 day')
)
SELECT d.dt, COALESCE(SUM(o.amount), 0) AS daily_revenue
FROM dates d
LEFT JOIN orders o ON o.order_date = d.dt
GROUP BY d.dt
ORDER BY d.dt;
Вопросы для оценки уровня PostgreSQL
Junior-уровень:
- Что такое
SERIAL/BIGSERIAL? - Чем
TEXTотличается отVARCHAR(n)?
Middle-уровень:
- Как работает
RETURNINGв INSERT/UPDATE? - Что такое
UPSERT(INSERT ... ON CONFLICT)?
Senior-уровень:
- Объясните разницу между
VACUUMиVACUUM FULL - Что такое
autovacuumи почему он важен? - Как работает MVCC в PostgreSQL?
Шкала оценки
| Тема | Junior | Middle | Senior |
|---|---|---|---|
| Базовые типы данных | ✓ | ✓ | ✓ |
| JSONB | — | Базово | Продвинуто |
| EXPLAIN | — | Читает | Оптимизирует |
| Индексы | Знает B-tree | Знает типы | Выбирает оптимальный |
| Временные зоны | — | ✓ | ✓ |
| MVCC, VACUUM | — | Слышал | Понимает |
Практические задачи по PostgreSQL с автоматической проверкой доступны на SQLlab.ru — идеально для подготовки к специфическому интервью по Postgres.