PostgreSQL: от устройства движка до продакшена

Вы научитесь находить по плану запроса, где база тратит время, и приносить правку с замером до и после, которую на ревью принимают по цифрам. Запрос вчера отвечал быстро, сегодня держит страницу, а новый индекс планировщик не берёт. Ставить ничего не нужно: каждая лабораторная поднимает свежий PostgreSQL 16 под вашу попытку, а вы пишете только SQL. Один индекс без правки текста запроса превращает 215 мс в 0,1 мс на таблице в два миллиона строк.

Чему вы научитесь

Сервис стоит, а база спокойна

Приложение пишет, что база висит, а процессор и диск спокойны. Вы идёте по порядку дежурного: находите ожидающих по wait_event_type = 'Lock', получаете держателя через pg_blocking_pids и смотрите, что он делает и как давно.

На картинке виновник — транзакция, которую открыли, изменили строку и бросили. За ней встают UPDATE той же строки, миграция с ALTER TABLE и даже обычные SELECT. Миграцию вы учитесь заворачивать в lock_timeout, чтобы она падала через две секунды, а не вставала в очередь.

Что показывает таблица после каждого UPDATE

UPDATE не правит строку на месте, а пишет новую версию. Обычный VACUUM возвращает место таблице, а не диску: в эксперименте файл остаётся 20 МБ во всех четырёх раундах.

Если открыта чужая транзакция со снимком, VACUUM не имеет права убрать мёртвые версии, и файл растёт: 20, 30, 40, 50 МБ. Виновника вы находите по backend_xmin. VACUUM FULL вернёт файл к 10 МБ, но на время перестройки блокирует таблицу, поэтому сначала подтверждают причину.

Что нужно знать

SQL на уровне SELECT с JOIN, GROUP BY и подзапросами, DDL вида CREATE TABLE и ALTER TABLE.

Готовность читать вывод сервера дословно: планы и сообщения об ошибках здесь главный рабочий инструмент.

Администрировать Linux не нужно: даже реплику в лабораторных поднимает песочница.

Где живёт отставание реплики

Репликация переносит на вторую машину журнал WAL. Разность sent_lsn и replay_lsn в pg_stat_replication показывает, сколько журнала реплика получила, но ещё не применила к данным. Поэтому «репликация работает» подтверждают не по запущенному процессу, а по state = streaming, отставанию в байтах и строкам, которые действительно есть на реплике.

Слот репликации заставляет primary хранить журнал, пока реплика его не заберёт. Забытый слот без потребителя растит pg_wal и может остановить primary по месту на диске.

Правка, которую принимают по плану

Для витрины категории вы разбираете три индекса под один запрос на одних данных. Индекс по (category_id, created_at) убирает сортировку, но оставляет проверку status после чтения. Индекс с status в середине закрывает запрос целиком, но весит больше. Частичный индекс даёт 22 страницы вместо 569.

У решения есть цена: для status = 'draft' частичный индекс не подходит, и сервер снова читает всю таблицу. Одна гипотеза, одна правка, замер до и после на тех же данных и проверка, что выдача не изменилась.

Для кого

Backend-разработчикам, которые уверенно пишут SQL, но не могут объяснить по плану, почему запрос стал медленным.

Тем, кто отвечает за базу своего сервиса: блокировки, раздутые таблицы, реплики, таймауты и миграции без простоя.

Аналитикам и инженерам данных, которым нужны планы, оконные функции и партиционирование.

Расследование на настоящем PostgreSQL

Каждая попытка — новый кластер PostgreSQL 16 в контейнере. Чекер создаёт его через initdb, заливает данные детерминированно, выполняет ваш solution.sql и сверяет результат запроса на двух наборах данных, план после ANALYZE или состояние системных каталогов. Ставить ничего не нужно, Linux администрировать тоже.

В модуле про репликацию песочница сама поднимает два кластера и делает pg_basebackup, а вы пишете только SQL: слоты, публикации, подписки и запросы к pg_stat_replication.

В итоговом проекте вы разгоняете медленный каталог без подсказок: топ запросов из pg_stat_statements, план узла-виновника, гипотеза с предиктом, одна правка и замер до и после. Завершает работу чек-лист надёжности перед выкладкой.

Фидбэк говорит, на каком наборе и что разошлось, а сообщения ERROR приходят от сервера дословно. Число попыток не ограничено.

Поддержка

Вы также можете задать любой вопрос по курсу у поддержки t.me/mentorix_support

Программа курса

Модулей: 12, уроков: 55. Задачи с кодом проверяются автоматически.

  1. Как PostgreSQL устроен изнутри: процессы, память, MVCC

  2. B-tree вглубь: составные, частичные и покрывающие индексы

  3. Специальные индексы: GIN, GiST, BRIN и выбор между ними

  4. Планы запросов: EXPLAIN, статистика и методы соединений

  5. Оптимизация запросов на практике

  6. Транзакции, блокировки и VACUUM

  7. WAL, репликация и восстановление

  8. Поиск и полуструктурированные данные: jsonb, FTS, нечёткий поиск

  9. Процедурный PostgreSQL: функции, триггеры, представления, права

  10. База и приложение: соединения, таймауты, идемпотентность

  11. Эксплуатация: мониторинг, обслуживание, миграции без простоя

  12. Итоговый проект: разгоняем медленный сервис

Стоимость курса: 11990 ₽

Открыть курс на Mentorix · Все курсы