執行計畫是一棵樹,從下往上讀

EXPLAIN 是用來查看或分析 SQL 的指令,三件事:

  • 分析效能:找出慢在哪、瓶頸在哪
  • 查看執行計畫:了解資料庫怎麼掃描資料表(全表掃描、索引掃描)以及執行順序
  • 協助判斷要不要建 index 來改善查詢速度
EXPLAIN SELECT * FROM users WHERE id = 1;

關鍵:那份輸出是一棵樹

query plan 的內容可以理解成樹狀結構的一種:每個節點會從下層節點或 table 取得資料,然後回傳給上層的節點做使用,然後在最頂端取得查詢結果。

縮排就是樹的層級,-> 就是子節點。把一份真實輸出攤平來看:

Sort (cost=717.34..717.59 rows=101) (actual time=7.761..7.774 rows=100 loops=1)
  Sort Key: t1.fivethous
  Sort Method: quicksort  Memory: 77kB
  -> Hash Join (cost=230.47..713.98 rows=101) (actual time=0.711..7.427 rows=100 loops=1)
       Hash Cond: (t2.unique2 = t1.unique2)
       -> Seq Scan on tenk2 t2 (actual time=0.007..2.583 rows=10000 loops=1)
       -> Hash (actual time=0.659..0.659 rows=100 loops=1)
            Buckets: 1024  Batches: 1  Memory Usage: 28kB
            -> Bitmap Heap Scan on tenk1 t1 (actual time=0.080..0.526 rows=100 loops=1)
                 Recheck Cond: (unique1 < 100)
                 -> Bitmap Index Scan on tenk1_unique1 (actual time=0.049..0.049 rows=100 loops=1)
                      Index Cond: (unique1 < 100)

畫成樹:

                    Sort              ← 查詢結果從這裡出來
                      │
                 Hash Join
                 ╱         ╲
        Seq Scan(tenk2)    Hash
         10000 列            │
                    Bitmap Heap Scan(tenk1)
                             │
                    Bitmap Index Scan(tenk1_unique1)
                             ↑ 資料從這裡開始往上流

資料一層一層往上交,最後執行的一定是最上面那個。

但「最深的先跑」不成立

上面這個 Hash Join 的例子裡,最深的 Bitmap Index Scan 確實先跑——因為 Hash Join 必須把一側完整收成 hash table 才能開始配對。 但這不是通則。 換成 Nested Loop,順序由「兄弟關係」決定而不是深度:上面那個子節點先跑,下面那個被它驅動。內層節點的搜尋條件裡會出現外層的欄位(Index Cond: (x = a.col)),外層沒跑,內層根本不知道要找什麼。 完整規則見 Nested Loop 的執行順序是上外下內,不是最深的先跑。

光看 rows 就能看出資料量在每一層怎麼變化:

Bitmap Index Scan → 100 列
Seq Scan(tenk2)   → 10000 列
Hash Join         → 100 列     ← 10000 和 100 配對之後剩 100
Sort              → 100 列

為什麼這個讀法要緊

因為時間是累積的。 最上層的 actual time=7.761..7.774 包含它所有子節點的時間;要找真正的瓶頸,得往下看是哪一層把時間吃掉的。

透過執行 EXPLAIN 指令,我們可以觀察 query 執行過程中哪些步驟耗費掉大量時間、或者是不合理,進而調整 query 或資料庫的設定來嘗試改善。

視覺化

輸出巢狀太深時用圖形化工具:https://explain.dalibo.com/

貼上計畫就會畫成可互動的樹,並把耗時最多的節點標出來。