Архитектура, индексы, транзакции и репликация
Ответ: PostgreSQL — это объектно-реляционная система управления базами данных с открытым исходным кодом, известная строгим соответствием стандарту SQL, расширяемостью и надёжностью.
Ответ: Обе СУБД реляционные и широко используются, но различаются подходом к соответствию стандартам и набору возможностей.
| Критерий | PostgreSQL | MySQL |
|---|---|---|
| Соответствие стандарту SQL | Высокое | Частичное, есть особенности диалекта |
| Типы данных | Богатый набор, включая JSONB, массивы, кастомные типы | Более ограниченный набор |
| Параллелизм | MVCC "из коробки" для всех движков хранения | Зависит от движка хранения (например, InnoDB) |
| Расширяемость | Высокая (расширения, кастомные функции и типы) | Ограниченная |
| Типичная область применения | Сложная бизнес-логика, аналитика, геоданные | Веб-приложения с простыми и быстрыми запросами |
Ответ: ACID — это набор из четырёх свойств, которые гарантируют надёжность транзакций в базе данных.
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
Ответ: MVCC (Multiversion Concurrency Control) — механизм, при котором PostgreSQL не блокирует строки на чтение: вместо этого каждая транзакция видит свой собственный "снимок" данных на момент начала транзакции.
VACUUMUPDATE фактически создаёт новую строку, а не изменяет существующую — это объясняет, зачем нужен VACUUM.
Ответ: VACUUM — это процесс обслуживания, который удаляет "мёртвые" (устаревшие) версии строк, оставшиеся после UPDATE и DELETE из-за механизма MVCC, освобождая место для повторного использования.
VACUUM orders; -- очистка таблицы orders
VACUUM ANALYZE orders; -- очистка + обновление статистики планировщика
VACUUM FULL orders; -- полная перезапись таблицы, требует блокировки
VACUUM не блокирует таблицу и может выполняться в фоне (autovacuum делает это автоматически)VACUUM FULL физически сжимает таблицу, но требует эксклюзивной блокировки — используется редкоОтвет: PostgreSQL поддерживает несколько типов индексов, оптимизированных под разные виды запросов.
| Тип индекса | Когда использовать |
|---|---|
| B-tree | По умолчанию; для равенства и диапазонных условий (=, <, BETWEEN, сортировка) |
| Hash | Только для точного равенства (=), не поддерживает диапазоны |
| GIN | Для составных значений: массивы, JSONB, полнотекстовый поиск |
| GiST | Для геометрических данных, диапазонов и полнотекстового поиска с ранжированием |
| BRIN | Для очень больших таблиц с естественной физической сортировкой (например, по времени) |
CREATE INDEX idx_orders_customer ON orders (customer_id);
CREATE INDEX idx_products_tags ON products USING GIN (tags);
Ответ: EXPLAIN показывает план выполнения запроса — как планировщик собирается его выполнить (какие индексы использует, порядок соединения таблиц), не выполняя запрос. EXPLAIN ANALYZE реально выполняет запрос и добавляет к плану фактическое время выполнения каждого шага.
EXPLAIN ANALYZE
SELECT * FROM orders
WHERE customer_id = 42
ORDER BY created_at DESC;
Seq Scan в выводе означает полное сканирование таблицы — обычно сигнал о том, что нужен индексIndex Scan означает использование индексаEXPLAIN ANALYZE реально выполняет запрос, поэтому для запросов с побочными эффектами (INSERT/UPDATE/DELETE) стоит оборачивать анализ в транзакцию с откатом.
Ответ: Уровень изоляции определяет, насколько параллельные транзакции защищены друг от друга от определённых аномалий чтения.
| Уровень изоляции | Описание |
|---|---|
| Read Committed | Уровень по умолчанию в PostgreSQL; каждый запрос внутри транзакции видит данные, зафиксированные к моменту его выполнения |
| Repeatable Read | Транзакция видит один и тот же снимок данных на протяжении всей своей работы, независимо от изменений других транзакций |
| Serializable | Самый строгий уровень — гарантирует, что результат параллельных транзакций эквивалентен их последовательному выполнению |
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- операции
COMMIT;
Ответ: PostgreSQL поддерживает два типа для хранения JSON: json хранит данные как текст и парсит при каждом обращении, а jsonb хранит их в бинарном разобранном виде, что быстрее для запросов и поддерживает индексацию.
CREATE TABLE events (
id SERIAL PRIMARY KEY,
payload JSONB
);
INSERT INTO events (payload)
VALUES ('{"type": "click", "user_id": 42}');
SELECT payload->>'type' AS event_type
FROM events
WHERE payload->>'user_id' = '42';
CREATE INDEX idx_events_payload ON events USING GIN (payload);
jsonb, а не json — единственный плюс json в том, что он сохраняет исходное форматирование и порядок ключей.
Ответ: Оконные функции выполняют вычисления над набором строк ("окном"), связанных с текущей строкой, но, в отличие от GROUP BY, не сворачивают результат в одну строку — каждая исходная строка остаётся в выводе.
SELECT
employee_id,
department,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_in_dept,
RANK() OVER (ORDER BY salary DESC) AS overall_rank
FROM employees;
PARTITION BY делит строки на группы, аналогично GROUP BY, но без схлопывания строкROW_NUMBER() присваивает уникальный порядковый номер, RANK() — с пропусками при равных значенияхОтвет: PostgreSQL использует потоковую репликацию (streaming replication), основанную на журнале упреждающей записи (WAL): все изменения данных сначала записываются в WAL, и именно этот поток передаётся на реплики.
Ответ: Партиционирование делит одну логическую таблицу на несколько физических частей (партиций) по заданному критерию, что упрощает обслуживание и ускоряет запросы к большим таблицам.
DELETE по условию
CREATE TABLE orders (
id SERIAL,
created_at DATE NOT NULL,
amount NUMERIC
) PARTITION BY RANGE (created_at);
CREATE TABLE orders_2024 PARTITION OF orders
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
CREATE TABLE orders_2025 PARTITION OF orders
FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');