Индексы, транзакции, MVCC — почему план меняется и куда деваются мёртвые строки.
Лекции
N+1, JOIN и prepared statements
N+1 — это N сетевых кругов вместо одного запроса, а не «сложная сортировка в планировщике». JOIN или батч-preload лечат чтение. Prepared statement снимает parse на горячем пути и не заменяет индекс.
Пул соединений и PgBouncer
Каждое клиентское соединение в PostgreSQL — отдельный серверный процесс. Лимит max_connections невелик. Пул в приложении и PgBouncer решают разные этажи одной задачи.
WAL, replay, лаг реплики и failover
WAL — журнал изменений: локальная durability и канал для физической реплики. Асинхронная реплика отстаёт. Failover — это promote и то, как клиенты найдут новый primary, а не «перезапустили под».
EXPLAIN ANALYZE: Seq Scan, Index Scan, buffers
EXPLAIN показывает оценку планировщика. EXPLAIN ANALYZE выполняет запрос и даёт фактические цифры. Читают actual rows против planned, тип узла и буферы, а не «стрелочки красивого дерева».
Блокировки строк, FOR UPDATE, deadlock
MVCC не отменяет локи писателей. FOR UPDATE берёт row lock без изменения данных. При тупике PostgreSQL прерывает одну транзакцию. Не держите лок, пока ходите в сеть.
MVCC, xmin/xmax, vacuum и bloat
UPDATE в PostgreSQL не переписывает строку на месте: появляется новая версия, старая жива, пока её кто-то может видеть. Vacuum подбирает мёртвое. Долгая транзакция удерживает горизонт и раздувает bloat.
Read Committed, Repeatable Read, Serializable
По умолчанию в PostgreSQL — Read Committed. Repeatable Read здесь это snapshot isolation. Serializable ловит write skew ценой ретраев по serialization_failure.
ACID коротко: зачем транзакция
Транзакция задаёт границу «всё или ничего» для нескольких изменений. ACID описывает свойства этой границы, а не магию изоляции и не бизнес-инварианты приложения.
Составной индекс и leftmost prefix
Индекс (a, b, c) работает как телефонная книга: сначала a, потом b. Без ведущей колонки классический B-tree почти бесполезен для поиска.
B-tree индексы, Seq Scan и covering
B-tree — индекс по умолчанию в PostgreSQL. Seq Scan не ошибка: на малой таблице или при низкой селективности он дешевле. Covering-индекс с INCLUDE даёт шанс на Index Only Scan.