1. 程式人生 > 其它 >使用explain分析sql語句————記一次優化

使用explain分析sql語句————記一次優化

技術標籤:sqlmysqlBNLmysql優化

直接上sql,省略必要條件,在測試環境分析,資料較少,但依舊可看出問題:

zl_transport_order 運單表,可理解為訂單表,id為運單id,transport_order_no為運單號
zl_package 包裹表,transport_order_id為運單id,transport_order_no為運單號

EXPLAIN SELECT
		t1.*
	FROM
		zl_transport_order AS t1
	JOIN zl_package AS t2 ON t1.id = t2.transport_order_id
	JOIN
zl_user_address_snapshot t3 ON t1.recipient_address_id = t3.id WHERE t1.active = 1 AND t1.state IN (0, 20, 40, 10, 30) GROUP BY t1.transport_order_no ORDER BY t1.create_date DESC

在這裡插入圖片描述
這條sql比較有問題的是用了臨時表和join buffer(使用BNL演算法)

簡單解釋下Extra的幾個引數 :
Using where:優化器需要通過索引回表查詢資料,除主鍵索引外,其餘索引只存索引欄位與主鍵,一般查詢欄位不在索引裡,就要回表,是正常的。

Using index:直接訪問索引就可獲取到所需資料,不需要回表(回到主鍵索引查詢),代表查詢欄位只有索引欄位和主鍵,只走一遍索引樹即可,查詢很快。

Using filesort :當Query中包含 ORDER BY 操作,而且無法利用索引完成排序操作的時,MySQL Query Optimizer不得不選擇相應的排序演算法來實現,資料較少時從記憶體排序,否則從磁碟排序,主要看要排序欄位的資料量,如果很大,建議建個索引,直接走索引排序。

Using join buffer (Block Nested Loop):將外層迴圈的行/結果集存入join buffer, 內層迴圈的每一行與整個buffer中的記錄做比較,從而減少內層迴圈的次數,多次掃描被驅動表,佔用磁碟 IO 資源,大表會佔用非常多CPU 資源,可能導致 Buffer Pool 的熱資料被淘汰,影響記憶體命中率,總之不要用。一般是被驅動表用不上索引,才使用BNL 演算法,可考慮建個索引解決。

先來解決Using join buffer (Block Nested Loop)的問題:被驅動表zl_package實際是有索引的,只是在欄位transport_order_no上,而zl_transport_order表上欄位transport_order_no也有索引 ,所以此處只是將表接連條件換成一個有索引 的欄位:

EXPLAIN SELECT
		t1.*
	FROM
		zl_transport_order AS t1
	JOIN zl_package AS t2 ON t1.transport_order_no= t2.transport_order_no
	JOIN zl_user_address_snapshot t3 ON t1.recipient_address_id = t3.id
	WHERE
		t1.active = 1
	AND t1.state IN (0, 20, 40, 10, 30) 
	GROUP BY
		t1.transport_order_no
	ORDER BY
		t1.create_date DESC

效果:在這裡插入圖片描述
最後來解決臨時表的問題:

EXPLAIN SELECT
		t1.*
	FROM
		zl_transport_order AS t1
	JOIN zl_package AS t2 ON t1.transport_order_no= t2.transport_order_no
 	JOIN zl_user_address_snapshot t3 ON t1.recipient_address_id = t3.id
	WHERE
		t1.active = 1
	AND t1.state IN (0, 20, 40, 10, 30) 
	GROUP BY
		t1.id
 	ORDER BY
		t1.id DESC

將GROUP BY與ORDER BY 後的欄位換成id ,效果跟之前是一樣的,但卻可以利用主鍵索引來排序,不需要再利用額外的空間排序

效果:
在這裡插入圖片描述
總之,使用explain,主要有三個關注點:
首先是extra,可能有些屬性不太常用,可以百度看看,思考下解決方案,嘗試多改改;
然後是key,看下有沒有用上索引,用上了哪個索引,如果建了索引但沒用上,思考下是什麼原因;
最後就是row,掃描行數,這個參考來看,如果有很多頁空洞可能會導致查詢不準。