Пошук уроків, статей та іншого контенту
Поглиблений погляд на індекси з практики читання EXPLAIN — як розпізнати повільний запит і чому.
Механіка самих індексів — навіщо вони потрібні, як влаштований B-tree, композитні індекси, коли додавати індекс — детально розібрана в статті «Індекси в PostgreSQL» (розділ Статті) і тут не повторюється. Цей урок фокусується на практичному навику, що спирається на розуміння індексів: читання виводу EXPLAIN, щоб зрозуміти, чому конкретний запит повільний, і чи справді індекс використовується так, як очікувалось.
EXPLAIN показує план, який планувальник запитів збирається виконати, — оцінку, без реального виконання запиту. EXPLAIN ANALYZE реально виконує запит і показує, окрім плану, ще й фактичний виміряний час і кількість рядків на кожному кроці — саме EXPLAIN ANALYZE потрібен для діагностики реальної, а не теоретичної продуктивності.
EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 42 ORDER BY created_at DESC;Index Scan using idx_orders_user_id on orders
(cost=0.29..8.31 rows=5 width=64)
(actual time=0.021..0.024 rows=4 loops=1)
Index Cond: (user_id = 42)
Planning Time: 0.15 ms
Execution Time: 0.04 msIndex Scan using idx_orders_user_id — підтверджує, що використано саме цей індекс, а не повне сканування таблиці.
cost=0.29..8.31 — оцінка планувальника (умовні одиниці, не мілісекунди) для старту й повного виконання цього кроку — корисна для порівняння варіантів плану між собою, не для абсолютного судження про швидкість.
rows=5 (оцінка) проти actual rows=4 (реальність) — велика розбіжність між оціненою й фактичною кількістю рядків сигналізує, що статистика планувальника застаріла (ANALYZE table_name; оновлює її вручну).
Execution Time — реальний виміряний час виконання, найкорисніше число для практичної діагностики повільного запиту.
Наявність індексу не гарантує, що планувальник ним скористається — для запитів, що відсіюють велику частку рядків таблиці (наприклад, WHERE is_active = true, якщо активних 90% рядків), Seq Scan (повне сканування) може бути дешевшим за Index Scan, бо читання майже всієї таблиці через індекс, а потім усе одно звернення до самих рядків, коштує дорожче за просто послідовне читання всієї таблиці одразу.
Побачити Seq Scan у плані — не завжди проблема. Проблема — коли Seq Scan з'являється там, де умова відсіює лише малу частку рядків (наприклад, конкретний user_id серед мільйона), а очікувався швидкий Index Scan; саме тоді варто перевірити наявність індексу й актуальність статистики (ANALYZE).
Використовувати EXPLAIN (без ANALYZE) для реальної діагностики продуктивності — це лише оцінка планувальника, без фактичного виміряного часу.
Панікувати від будь-якого Seq Scan у плані без перевірки, чи справді умова запиту відсіює малу частку таблиці, — Seq Scan часом дійсно є найшвидшим правильним вибором планувальника.
Ігнорувати велику розбіжність між оціненими (rows=) і фактичними (actual rows=) значеннями — типова ознака застарілої статистики, яку потрібно оновити командою ANALYZE.
EXPLAIN ANALYZE показує не лише теоретичний план запиту, а й реально виміряний час і кількість рядків на кожному кроці — основний інструмент діагностики того, чи використовується очікуваний індекс і де саме витрачається час повільного запиту. Розбіжність між оціненою й фактичною кількістю рядків сигналізує застарілу статистику; Seq Scan замість Index Scan не завжди помилка — залежить від того, яку частку таблиці відсіює умова запиту.