CAS
776
2025-03-31
每條SQL語句,MySQL都會經過成本和規則的優化,對這個SQL選擇對應的一些訪問方法和順序,包括做一些特殊的改寫確保執行效率是最優的,然后優化過后,就會得到一個執 行計劃。
執行計劃,落實到底層,無非就是先訪問哪個表,用哪個索引還是全表掃描,拿到數據后如何回表,是否要基于臨時磁盤文件做分組聚合或者排序。
簡單的單表查詢,可能這就一條數據,代表它打算如何訪問這一個表。
explain select * from t1
這里直接會掃描表的聚簇索引的葉節點,按順序掃描過去拿到表里全部數據。
rows=32,說明這個表里就32條數據,全表掃描會全掃出來
?ltered=100%,無where過濾條件,所以直接篩選出來的數據就是表里數據的100%占比。
1 多表關聯語句
explain select * from t1 join t2
這種關聯語句會選擇一個表先查詢出來數據, 接著遍歷每一條數據去另外一個表里查詢可以關聯在一起的數據,然后關聯。
因為是多表關聯,其執行計劃分為兩條,即會訪問兩個表:
第一個表t1,先用ALL方式全表掃描,掃出xxx條數據
第二個表訪問t2,同樣ALL全表掃描,這種多表關聯是笛卡爾積,t1表的每條數據都會去t2表全表掃描所有yyy條數據,跟t2表的每條數據都會關聯。extra是Nested Loop(MySQL5.7 老版本值,8.0 版本為圖中所示的優化),即嵌套循環的訪問方式
兩條執行計劃的id都是1,一般執行計劃里,一個SELECT會對應一個id,因為這兩條執行計劃對應的是一個SELECT語句,所以他們倆的id都是1,是一樣。
如果你要是有一個子查詢,有另外一個SELECT,那么另外一個SELECT子查詢對應的執行計劃的id就是2。
2 包含子查詢
explain select * from citizen where name in (select name from user) or age = 18;
主SELECT語句的WHERE篩選條件是依賴子查詢,還有一個自己的WHERE篩選條件。
該SQL里有兩個SELECT:
主查詢SELECT的執行計劃的id=1
子查詢SELECT的執行計劃的id=2
第一個執行計劃的select_type=PRIMARY,查詢類型是主查詢。主查詢有個where條件age=18,所以其possible_keys包含age索引,但key是NULL且type是ALL,說明沒選擇age字段索引,而是全表掃描,why?可能MySQL分析成本,使用age字段索引掃描18這個值,幾乎就跟全表掃描差不多,可能age字段值幾乎都是18,所以最后就選擇還不如直接全表掃描。
第二個執行計劃select_type=SUBQUERY,即子查詢,子查詢針對t2表,子查詢本身就是個全表查詢,但對主查詢而言,會使用name in篩選條件,type=index,說明使用了掃描name字段的二級索引,直接掃描name二級索引,來跟子查詢的結果集做比對。
3 union SQL
EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2
這是一個典型的union語句,把兩個表的查詢結果合并起來。
執行計劃的:
第一、二條,兩個SELECT子句對應兩個id,分別從t1、t2表里全表掃描
第三條,union子句默認把兩個結果集合并且去重,所以該執行計劃其實就是去重
所以其table=
SQL
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。