在上一篇文章《用Explain 命令分析 MySQL 的 SQL 執行》中,咱們講解了 Explain 命令的詳細使用。可是它只能展現 SQL 語句的執行計劃,沒法展現爲何一些其餘的執行計劃未被選擇,好比說明明有索引,可是爲何查詢時未使用索引等。爲此,MySQL 提供了 Optimizer Trace 功能,讓咱們能更加詳細的瞭解 SQL 語句執行的全部分析,優化和選擇過程。sql
若是您想更深刻地瞭解爲何選擇某個查詢計劃,那麼優化器跟蹤很是有用。雖然 EXPLAIN 顯示選定的計劃,但Optimizer Trace 能顯示爲何選擇計劃:您將可以看到替代計劃,估計成本以及作出的決策。本篇文章會詳細講解 Optimizer Trace 展現的全部相關信息,而且會輔之一些具體使用案例。學習
在瞭解 Optimizer Trace 的以前,咱們先來學習一下 MySQL 是如何選擇衆多執行計劃的。優化
MySQL 會使用一個基於成本(cost)的優化器對執行計劃進行選擇。每一個執行計劃的成本大體反應了該計劃查詢所須要的資源,主要因素是計算查詢時將要訪問的行數。優化器主要根據從存儲引擎獲取數據的統計數據和數據字典中元數據信息來作出判斷。它會決定是使用全表掃描或者使用某一個索引進行掃描,也會決定表 join的順序。優化器的做用以下圖所示。.net
優化器會爲每一個操做標上成本,這些成本的基準單位或最小值是從磁盤讀取隨機數據頁的成本,其餘操做的成本都是它的倍數。因此優化器能夠根據每一個執行計劃的全部操做爲其計算出總的成本,而後從衆多執行計劃中,選取成本最小的來最終執行。3d
既然是基於統計數據來進行標記成本,就總會有樣本沒法正確反映總體的狀況,這也是 MySQL 優化器有時作出錯誤優化的重要緣由之一。code
首先,咱們來看一下具體如何使用 Optimizer Trace。默認狀況下,該功能是關閉的,你們可使用以下方式打開該功能,而後執行本身須要分析的 SQL 語句,而後再從 INFORMATION_SCHEMA 的 OPTIMIZER_TRACE中查找到該 SQL 語句執行優化的相關信息。blog
# 1. 打開optimizer trace功能 (默認狀況下它是關閉的): SET optimizer_trace="enabled=on"; SELECT ...; # 這裏輸入你本身的查詢語句 SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE; # 當你中止查看語句的優化過程時,把optimizer trace功能關閉 SET optimizer_trace="enabled=off";
這個 OPTIMIZER_TRACE 表有4個列,以下所示:索引
QUERY
:表示咱們的查詢語句。TRACE
:表示優化過程的JSON格式文本。MISSING_BYTES_BEYOND_MAX_MEM_SIZE
:因爲優化過程可能會輸出不少,若是超過某個限制時,多餘的文本將不會被顯示,這個字段展現了被忽略的文本字節數。INSUFFICIENT_PRIVILEGES
:表示是否沒有權限查看優化過程,默認值是0,只有某些特殊狀況下才會是1
,咱們暫時不關心這個字段的值。其中,信息最多也最爲重要的就是第二列 TRACE,它也是咱們後續分析的重點。資源
TRACE 列的內容是一個超級大的 JSON 數據,直接展開而後一條一條解析估計能看到大夥腦袋疼。rem
因此,咱們先來看一下這坨大 JSON 的骨架。它有三大塊內容,也表明着 SQL 語句處理的三個階段,分別爲準備階段,優化階段和執行階段。
接下來,咱們詳細介紹一個案例,在案例中介紹涉及到的具體字段和含義。
首先,SQL 語句查詢不使用索引的狀況有不少,咱們這裏只討論由於基於成本的優化器認爲全表查詢執行計劃的成本低於走索引執行計劃的狀況。
以下圖這個場景,明明 val 列上有索引,而且 val 現存值也有必定差別性,爲何沒有使用索引進行查詢呢?
咱們按照上文使用 Optimizer Trace 找到其 join_optimization 中 range_analysis 相關數據,它會展現 where 從句範圍查詢過程當中索引的選擇狀況
由上圖能夠看出,MySQL 對比了全表掃描和使用 val 做爲索引兩個方案的成本,最後發現雖然全表掃描須要掃描更多的行,可是成本更低。因此選擇了全表掃描的執行方案。
這是爲何呢?明明使用 val 索引能夠少掃描 4 行。這其實涉及 InnoDB 中使用索引查詢數據行的原理。
Innodb引擎查詢記錄時在沒法使用索引覆蓋(也就是須要查詢的數據多與索引值,好比該例子中,我要查name,而索引列是 val)的場景下,須要作回表操做獲取記錄的所需字段,也就是說,經過索引查出主鍵,再去查數據行,取出對應的列,這樣勢必是會多花費成本的。
因此在回表數據量比較大時,常常會出現 Mysql 對回表操做查詢代價預估代價過大而致使不使用索引的狀況。
通常來講,當SQL 語句查詢超過表中超過大概五分之一的記錄且不能使用覆蓋索引時,會出現索引的回表代價太大而選擇全表掃描的現象。且這個比例隨着單行記錄的字節大小的增長而略微增大。
經過 range_analysis 中的相關數據也能夠對 where 從句使用多個索引列,如何選擇執行時使用的索引的狀況進行分析。
終於,介紹了有關於 MySQL 語句執行分析的 explain 和 Optimizer Trace,下一篇,咱們將分析具體的死鎖場景。