[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-postgresql-kak-chitat-plan-vypolneniya-zaprosa":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":15,"progress":16,"seo":17},942,"kak-chitat-plan-vypolneniya-zaprosa",28,"postgresql","PostgreSQL","🐘","Как читать план выполнения запроса?","План выполнения — это дерево узлов (nodes). Выполнение идёт от внутренних узлов к внешним (снизу вверх). Чтение плана — ключевой навык для оптимизации SQL.\n\n### Основные типы узлов сканирования\n\n| Узел | Описание |\n|---|---|\n| `Seq Scan` | Последовательное чтение всей таблицы |\n| `Index Scan` | Чтение через индекс, затем обращение к таблице за данными |\n| `Index Only Scan` | Все нужные данные уже есть в индексе |\n| `Bitmap Index Scan` + `Bitmap Heap Scan` | Двухфазное: сначала собирается битовая карта по индексу, затем читаются страницы |\n\n### Типы соединений (JOIN)\n\n| Узел | Описание |\n|---|---|\n| `Nested Loop` | Для каждой строки внешнего набора ищем во внутреннем. Хорош при малом внешнем наборе |\n| `Hash Join` | Строится хеш-таблица по одной стороне. Эффективен для больших наборов |\n| `Merge Join` | Оба набора сортируются, затем сливаются. Эффективен, если данные уже отсортированы |\n\n\u003Cdetails>\u003Csummary>Пример чтения сложного плана\u003C\u002Fsummary>\n\n```sql\nEXPLAIN ANALYZE\nSELECT t.id, t.amount, c.name\nFROM transactions t\nJOIN clients c ON t.client_id = c.id\nWHERE t.created_at > '2024-01-01'\n  AND t.amount > 50000;\n```\n\n```\nHash Join  (cost=30.00..150.00 rows=100 width=48) (actual time=0.5..2.1 rows=87 loops=1)\n  Hash Cond: (t.client_id = c.id)\n  ->  Bitmap Heap Scan on transactions t  (cost=10.00..120.00 rows=100 width=24) (actual time=0.3..1.5 rows=87 loops=1)\n        Recheck Cond: (created_at > '2024-01-01')\n        Filter: (amount > 50000)\n        Rows Removed by Filter: 213\n        ->  Bitmap Index Scan on idx_tx_date  (cost=0.00..9.97 rows=300 width=0) (actual time=0.2..0.2 rows=300 loops=1)\n              Index Cond: (created_at > '2024-01-01')\n  ->  Hash  (cost=15.00..15.00 rows=500 width=32) (actual time=0.1..0.1 rows=500 loops=1)\n        Buckets: 1024  Batches: 1  Memory Usage: 40kB\n        ->  Seq Scan on clients c  (cost=0.00..15.00 rows=500 width=32) (actual time=0.01..0.05 rows=500 loops=1)\nPlanning Time: 0.2 ms\nExecution Time: 2.3 ms\n```\n\n\u003C\u002Fdetails>\n\n### На что обращать внимание\n\n- **Большое расхождение между estimated и actual rows** — устаревшая статистика, нужен `ANALYZE`\n- **Seq Scan на большой таблице с фильтром** — возможно, не хватает индекса\n- **Rows Removed by Filter** — строки прочитаны, но отброшены; признак неоптимального индекса\n- **Buffers: shared read** — чтение с диска (медленно), **shared hit** — чтение из кеша\n\n> **На собеседовании:** не нужно помнить все типы узлов. Покажите, что умеете читать план: снизу вверх, сравнивать estimated vs actual rows, искать Seq Scan на больших таблицах и «Rows Removed by Filter». Это три красных флага, которые решают 80% проблем производительности.","","middle",[7],[],null,{"title":18,"description":19,"ogTitle":18,"ogDescription":20,"keywords":21,"schemaAnswer":19,"featuredSnippetReady":22},"Как читать план выполнения запроса? — Gymterview","План выполнения — это дерево узлов (nodes). Выполнение идёт от внутренних узлов к внешним (снизу вверх). Чтение плана — ключевой навык для оптимизации SQL.","План выполнения — это дерево узлов (nodes). Выполнение идёт от внутренних узлов к внешним (снизу вверх). Чтение плана — ",[7,13],true]