本教學說明如何使用 Explain 報表來定位並修正有問題(速度慢)的查詢。它使用 DBT-3 資料庫,並從以下簡單的查詢範例開始。
SELECT * FROM orders
WHERE YEAR(o_orderdate) = 1992 AND MONTH(o_orderdate) = 4
AND o_clerk LIKE '%0223';
如下圖所示,查詢範例首先在視覺化 SQL 編輯器中執行。接下來,透過從 orders
資料表上方時,會顯示相關資訊。
或者,您可以切換至表格化 Explain,如下圖所示。使用下拉式清單在視覺化和表格化表示之間切換。
關於查詢的問題
為什麼這個查詢會產生完整資料表掃描?
為什麼已建立索引的
o_orderdate
資料行遺失了,未被列為可能的索引鍵?
仔細觀察,也會注意到已建立索引的資料行在運算式中使用,例如 "WHERE YEAR(o_orderdate) = 1992 AND MONTH(o_orderdate) = 4"
,因此未使用索引。若要使用現有的索引,您可以調整查詢如下。
SELECT * FROM orders
WHERE o_orderdate BETWEEN '1992-04-01' AND '1992-04-30'
AND o_clerk LIKE '%0223';
更新後的查詢範例會產生一個視覺化 Explain 圖像,其中 索引範圍掃描
取代了上一個查詢範例產生的 完整資料表掃描
。接下來的兩張圖顯示了修改後的查詢範例的視覺化和表格化表示。
請注意這些差異。類型從 ALL
變更為 range
,可能的索引鍵(和已使用的索引鍵)從 NULL
變更為 i_o_orderdate
,而掃描的列數從 150 萬變更為約 33000。儘管如此,掃描 33000 列卻只傳回 18 列是不必要的,因此可以將重點轉移到 o_clerk
資料行。下一個查詢範例(和表格化 Explain 圖)會新增以下索引,應可提高效能。
CREATE INDEX i_o_clerk ON orders(o_clerk);
新的索引未被視為可能的索引鍵,因為查詢正在搜尋 o_clerk
資料行的後綴,而索引不適用於後綴(雖然它們適用於前綴)。相反地,這個簡單的範例可以使用完整的職員 ID。調整查詢如下所示,會顯示更好的結果。
SELECT * FROM orders
WHERE o_orderdate BETWEEN '1992-04-01' AND '1992-04-30'
AND o_clerk LIKE 'Clerk#000000223';
以下圖示分別顯示更新後的查詢範例在視覺化 Explain 和表格化 Explain 中的效果。
新的 o_clerk
索引被考慮並使用,查詢掃描了 1546 列而不是 32642 列,查詢執行時間從 0.281 秒縮短到 0.234 秒。然而,EXPLAIN
估計這個查詢掃描 1546 列以傳回 18 列。在再次檢閱查詢之後,請考慮多欄索引可以滿足 WHERE
子句的條件,該子句基於 o_orderdate
和 o_clerk
資料行,如下一個陳述式所示。
CREATE INDEX io_clerk_date ON orders(o_clerk, o_orderdate)
o_clerk
在索引中顯示為第一欄,因為 o_orderdate
使用範圍。
現在,執行調整後的查詢會產生更好的結果。估計掃描和傳回了 18 列,並且查詢範例的執行時間為 0.234 秒,如下一個視覺化 Explain 和表格化 Explain 圖所示。
下表總結了本教學中對查詢所做的修改結果。
表 7.2 DBT-3 Explain 教學查詢比較
類型 | 可能的索引鍵 | 索引鍵 | 掃描的列數 | 持續時間(秒) | 額外資訊 | 傳回的列數 |
---|---|---|---|---|---|---|
all | NULL | NULL | 1.50M | 1.201 | 使用 where | 18 |
range | i_o_orderdate | i_o_orderdate | 32642 | 0.281 | 使用索引條件;使用 where | 18 |
range | i_o_orderdate, i_o_clerk | i_o_clerk | 1546 | 0.234 | 使用索引條件;使用 where | 18 |
range | i_o_orderdate, i_o_clerk, i_o_clerk_date | i_o_clerk_date | 18 | 0.234 | 使用索引條件 | 18 |