遇到 SQL 查詢效能不彰時,除了 review SQL 以外,使用 EXPLAIN 可以了解效能低落的原因。
這篇文章介紹如何使用這個指令及解讀回傳的結果。
Query Process
要解釋 EXPLAIN 前,需要了解 PostgreSQL 在查詢的內部流程。主要有下列步驟:
- Parser: 如同編譯器一樣,PostgreSQL 需要將人看的懂的 SQL 翻譯成它能執行的語言 (query tree)
- Rewrite: 調整 query tree,分解 views 到對應的 table
- Planner: 由 query tree 規劃該如何快速地找到資料。這個步驟跟 query 效能直接相關
- Execute: 執行 query
使用 EXPLAIN 能讓我們知道 query 會如何執行,接下來說明它的用法。
EXPLAIN
基本的用法是在 SQL 最前面加上 EXPLAIN
,則查詢結果回傳 query plan。也就是預估每次下 SQL 查詢時,背後的 planner 讀取多少 row, index 並且花了多少資源。
假如要真的執行 SQL,可使用 EXPLAIN ANALYZE
,則 PG 會執行並分析此 SQL。
以下面 SQL 為例:
1 | EXPLAIN SELECT * |
回傳結果會是
逐一分析結果:
- Hash Join (cost=20.18..43.69 rows=5 width=120) 執行 JOIN 的預估,此操作需要將一張表讀進 memory 再根據條件找出記錄
- cost 是猜測此 SQL 要花多少時間執行。裡面包含二個數字: 前者為隨機找二筆記錄需要的時間;後者表示逐一檢視記錄的總成本
- rows 為猜測需要掃描多少筆記錄
- width 為猜測平均每筆記錄的長度 (bytes)
- Hash Cond: (address.employee_id = employees.id) 使用 employee id 去 address table 找對應的記錄
- -> Seq Scan on address (cost=0.00..20.70 rows=1070 width=48) 逐一掃描 address 的成本
- -> Hash (cost=20.12..20.12 rows=4 width=72)
- -> Seq Scan on employees (cost=0.00..20.12 rows=4 width=72) 逐一掃描 employees 的預估成本
- Filter: (first_name = ‘Alex’::text) 使用 first_name 當查詢條件
在 query planner 階段,PostgreSQL 會比較隨機找出記錄和逐一掃描 heap file 需要的成本。
如果使用 index,會從 B+ tree root node 隨機找 child page 再搜尋對應的 heap file。一般來說,會比逐一找記錄來的快。
假如使用 pgadmin 的話有按鈕可以執行 EXPLAIN
它也可以用圖形的方式呈現 query plan
要注意使用 GUI 就不用在 SQL 加上 EXPLAIN
除了 Join 的 query plan, PostgreSQL 官方文件有列出各種 EXPLAIN 結果。如:
1 | EXPLAIN SELECT * FROM tenk1 WHERE unique1 = 42; |
此 SQL 使用 index column 查詢,query planner 呈現 index scan 結果。
在調校 SQL query 時,可藉由 EXPLAIN 分析需要的成本及過程。