SQLLab
Все статьи

PostgreSQL на собеседовании: специфика и задачи

Вопросы и задачи по PostgreSQL для технического интервью: специфичные функции, EXPLAIN, типы данных, JSON.

25 февраля 2026 г.·4 мин чтения·

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 Scan vs Index 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?

Шкала оценки

ТемаJuniorMiddleSenior
Базовые типы данных
JSONBБазовоПродвинуто
EXPLAINЧитаетОптимизирует
ИндексыЗнает B-treeЗнает типыВыбирает оптимальный
Временные зоны
MVCC, VACUUMСлышалПонимает

Практические задачи по PostgreSQL с автоматической проверкой доступны на SQLlab.ru — идеально для подготовки к специфическому интервью по Postgres.

Похожие статьи

Попробуй на практике

Тренажёр с реальными задачами — бесплатно и без регистрации

Открыть тренажёр →