linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Главы
  • How it worksскоро
  • Уроки
  • База знаний
  • Собеседование
home/postgres/lessons/pg-lab-28-1-joins

lesson ── postgres-labs ── ~24 мин ── 5 шагов

Получи hash, merge и nested loop на одном JOIN

Один и тот же JOIN выполним всеми тремя алгоритмами: hash по умолчанию, nested loop через тумблеры и индекс, и посмотрим, как нехватка work_mem заставляет hash проливаться на диск. Запусти psql во вкладке client.

▶ интерактивный sandbox

Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.

запустить sandbox →

stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    Подготовь две большие таблицы

    sql
    CREATE TABLE a AS SELECT g AS id FROM generate_series(1, 100000) g;
    CREATE TABLE b AS SELECT g AS id FROM generate_series(1, 100000) g;
    ANALYZE a; ANALYZE b;
    подсказка

    Без индексов и на больших входах планировщик предпочтёт hash join.

    ✓ Обе таблицы готовы.

  2. 02

    По умолчанию - Hash Join

    sql
    EXPLAIN SELECT * FROM a JOIN b USING(id);

    Большие входы, соединение по равенству, индексов нет - hash join.

    подсказка

    Hash join читает оба входа один раз, строит хеш по меньшему.

    ✓ Hash Join, как и ожидалось для больших входов.

  3. 03

    Выключи hash и merge - останется nested loop

    Тумблеры enable_* штрафуют алгоритм. Выполни в одной сессии:

    sql
    SET enable_hashjoin = off;
    SET enable_mergejoin = off;
    EXPLAIN SELECT * FROM a JOIN b USING(id);

    Останется Nested Loop. Это только план (без ANALYZE), выполнять его на больших таблицах не нужно.

    подсказка

    enable_* - инструмент для учёбы и диагностики, не для прода.

    ✓ С выключенными hash и merge остался Nested Loop.

  4. 04

    Маленький внешний вход + индекс = настоящий nested loop

    sql
    CREATE INDEX ON b(id);
    ANALYZE b;
    EXPLAIN SELECT * FROM a JOIN b USING(id) WHERE a.id < 5;

    Мало внешних строк и индекс на b - планировщик сам выбирает Nested Loop с Index Scan по b.

    подсказка

    Nested loop хорош, когда внешний вход мал, а на внутренней есть индекс.

    ✓ Маленький внешний вход + индекс - Nested Loop по выбору планировщика.

  5. 05

    Малый work_mem - hash проливается на диск

    sql
    SET work_mem = '64kB';
    EXPLAIN ANALYZE SELECT * FROM a JOIN b USING(id);

    У узла Hash смотри Batches. С крошечным work_mem хеш не влезает в память и делится на много пакетов (Batches > 1) с проливом на диск.

    подсказка

    Batches: 1 - всё в памяти; больше - был пролив на диск.

    ✓ Batches > 1 - hash join пролился на диск из-за малого work_mem.

Что ты узнал

Три алгоритма соединения: hash (большие входы по равенству, нужен work_mem), nested loop (мал внешний вход + индекс внутри), merge (отсортированные входы). Тумблеры enable_* показывают каждый. Нехватка work_mem заставляет hash делиться на batches и проливаться на диск.

команды

  • EXPLAIN SELECT * FROM a JOIN b USING(id);посмотреть алгоритм соединения
  • SET enable_hashjoin = off;увести план на другой алгоритм (для учёбы)
  • SET work_mem = '64MB';больше памяти - меньше пролива hash на диск

концепции

  • · hash join - один проход по каждому входу, только по равенству
  • · nested loop выгоден при малом внешнем входе и индексе на внутренней
  • · merge join сливает отсортированные входы за проход
  • · Batches > 1 - hash не влез в work_mem и пролился на диск

← предыдущая

Проведи запрос от Seq Scan до Index-Only Scan

следующая →

Понаблюдай порядок соединений и кеш плана

Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки