open atlas
↑ К треку
SQL и PostgreSQL вглубь SQL · 00 · 02

Как Postgres выполняет запрос

Запрос проходит пять стадий — parse, analyze, rewrite, plan, execute — прежде чем вернётся хоть одна строка. Знание конвейера говорит, куда уходит время и какая проблема живёт на какой стадии.

SQL Junior ◷ 14 min
Уровень
ОсновыJuniorMiddleSenior

Ты набираешь SELECT * FROM orders WHERE id = 42; и строка возвращается за миллисекунду. Кажется атомарным — будто база просто посмотрела значение. Это вовсе не атомарно: твой текст прошёл пять отдельных стадий, и на каждой живёт свой класс багов или тормозов. Когда запрос медленный, первый сеньорский вопрос всегда: «медленный на какой стадии?»

Пять стадий

Твоя SQL-строка не выполняется напрямую. Backend Postgres, владеющий твоим соединением, проталкивает её через конвейер:

  1. Parse — сырой текст проверяется на синтаксис и превращается в parse tree (дерево разбора — внутреннее представление запроса в виде узлов). Пропущенная запятая или SELCT умирают здесь. Таблицы ещё не трогаются; парсер даже не знает, существует ли orders.
  2. Analyze (семантика) — имена разрешаются по каталогу. Существует ли orders? Есть ли колонка id? Какие типы участвуют? Ошибка «column does not exist» рождается здесь, а не в парсере.
  3. Rewrite — применяются rule-based преобразования. Главное: запрос к представлению (view) переписывается в запрос к нижележащим таблицам; сюда же внедряются политики row-level security и правила.
  4. Plan / optimizeпланировщик берёт проанализированное дерево запроса и строит физический план: какой скан (sequential? index?), какой алгоритм join (nested loop? hash? merge?), в каком порядке. Он использует статистику таблиц, чтобы оценить число строк, и выбирает самый дешёвый план по внутренней стоимостной модели.
  5. Execute — исполнитель обходит выбранное дерево плана, протягивая строки сквозь него узел за узлом, и стримит результат тебе.

Вместе эти пять стадий означают, что к моменту, когда строка доходит до тебя, она уже прошла валидацию, разрешение имён, преобразование, оптимизацию и фактическое чтение — и на каждом из этих шагов может возникнуть сбой независимо. Не понимать хотя бы одну стадию — значит гадать, когда что-то идёт не так.

Почему стадии важны для отладки

Когда запрос ведёт себя неправильно, большинство инженеров сразу переписывают SQL — и тратят час, меняя текст, который никогда не был проблемой. Конвейер даёт более быстрый путь: сопоставь симптом со стадией, исправь именно там.

Конвейер — это диагностическая карта. Сопоставь симптом со стадией:

  • Синтаксическая ошибка → стадия parse. Чисто текстовая проблема; схема не важна.
  • «relation/column does not exist» → стадия analyze. Текст — валидный SQL, но не совпадает с каталогом.
  • Запрос внезапно медленный после загрузки данных → стадия plan. Оценки строк у планировщика устарели, и он выбрал плохой план. Фикс обычно — ANALYZE, чтобы обновить статистику, а не переписывание запроса.
  • Запрос всегда медленный, план выглядит верно → стадия execute. План в порядке, но он реально читает слишком много страниц; фикс — индекс или меньше данных, что меняет, какие планы вообще доступны.

Поэтому сеньорский рефлекс — EXPLAIN. EXPLAIN <query> показывает план, выбранный планировщиком, не выполняя запрос; EXPLAIN ANALYZE <query> выполняет его и показывает оценочные против фактических строк в каждом узле. Зазор между оценкой и фактом — самое полезное число в работе над производительностью Postgres: он говорит, обманули ли планировщик устаревшей статистикой.

-- Только план (быстро, без выполнения):
EXPLAIN SELECT * FROM orders WHERE id = 42;

-- Выполнить и сравнить оценку с реальностью:
EXPLAIN ANALYZE SELECT * FROM orders WHERE id = 42;
↻ задержка

Ты пока не прочитаешь план целиком — это отдельный раздел дальше (08-internals-and-tuning), а трек databases глубоко разбирает планировщик и внутренности планов выполнения. Сейчас усвой только форму: текст внутрь, пять стадий, строки наружу, а EXPLAIN — твоё окно в четвёртую стадию.

Почему это работает

Зачем вообще отделять планирование от выполнения? Потому что планирование дорого — для запроса, соединяющего шесть таблиц, число возможных порядков join’ов взрывается, и планировщик делает реальную комбинаторную работу, чтобы найти дешёвый. Postgres платит эту цену один раз и (с prepared statements) может переиспользовать план во многих выполнениях. Это также значит, что тот же распарсенный запрос можно перепланировать позже при лучшей статистике. Слить план и выполнение вместе — потерять оба выигрыша. Глава об execution-plans трека databases глубоко копает стоимостную модель, ведущую четвёртой стадией.

Викторина

Ты запускаешь запрос и получаешь 'column "emial" does not exist'. Какая стадия породила эту ошибку?

Викторина

Вчера запрос был быстрым; сегодня, после большого bulk INSERT, он в 50× медленнее при том же тексте. Лучший первый шаг?

Закончи аналогию

Заполни пропуск: EXPLAIN показывает выбранный планировщиком план _______ выполнения запроса, тогда как EXPLAIN ANALYZE выполняет его и сообщает фактические тайминги и число строк.

Вспомните перед уходом
  1. 01
    Перечисли пять стадий, через которые проходит запрос, по порядку, одним словом о каждой.
  2. 02
    Запрос внезапно медленный после bulk-загрузки, хотя текст не менялся. Какая стадия виновата и в чём фикс?
  3. 03
    В чём разница между EXPLAIN и EXPLAIN ANALYZE и почему важен зазор оценка-против-факта?
Итог

Запрос не ищется атомарно — он проходит пятистадийный конвейер: parse (синтаксис в дерево), analyze (разрешение имён по каталогу), rewrite (разворачивание views, внедрение row-level security), plan (стоимостный оптимизатор превращает дерево запроса в физический план сканов и join’ов) и execute (исполнитель обходит план и стримит строки). Ценность знания конвейера — диагностическая: синтаксическая ошибка — это parse, ошибка отсутствующей колонки — analyze, внезапное замедление после загрузки — стадия plan, лишённая свежей статистики (фикс — ANALYZE), а хронически медленный, но корректный план — стадия execute, делающая слишком много I/O (фикс — индекс). EXPLAIN показывает выбранный план; EXPLAIN ANALYZE выполняет его и обнажает зазор оценка-против-факта. Теперь, когда после bulk-загрузки запрос внезапно просядет в 50 раз, ты не будешь переписывать SQL — ты запустишь ANALYZE, откроешь EXPLAIN ANALYZE и посмотришь зазор между оценкой и фактом: именно там живёт ответ.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 4 завершено
Связанные уроки

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.