my sql explain & select

43
MySQL 的 SELECT 的的的 EXPLAIN Present by MingIn 1

Upload: ming-ying-wu

Post on 17-Aug-2015

47 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: My sql explain & select

MySQL 的 SELECT 優化與 EXPLAIN

Present by MingIn

1

Page 2: My sql explain & select

Outline

• MySQL 查詢優化• MySQL Explain• MySQL Profiles• Xboard 範例• Conclusion

2

Page 3: My sql explain & select

MySQL 查詢優化

• 目標:

– 了解 MySQL 如何執行查詢– 了解查詢高低效率的原因何在– 如何充分發揮 MySQL 的優勢,避開它的弱點

3

Page 4: My sql explain & select

為什麼查詢的效能不佳?

• 典型效能低落案例– 1. 查詢不必要的紀錄– 2. 多表關聯查資料的時候 (join or subqueries) ,返回全部 rows 資

料– 3. 總是取出全部的列資料– 4. 一直重複查詢相同的資料數據

4

Page 5: My sql explain & select

如何評估查詢的效能?

• 1. 指令回覆時間 = 服務執行時間 + 排隊等待時間• 2. 掃描的行數&返回的行數:以 10:1 ~ 1:1 為佳 • 3. 掃描的行數&查詢的類型 (explain:type & rows)

5

Page 6: My sql explain & select

查詢速度由好到壞

• 1. where 條件使用在 primary key 上 (system)• 2. where 條件使用在 index 上 (type:using index)• 3. where 條件使用在一般資料上 (type:using where)

6

Page 7: My sql explain & select

一個複雜的查詢 VS 多個簡單查詢? (1/2)

• 一個複雜的查詢

– SELECT post.* – FROM tag– JOIN tag_post ON tag_post.tag_id = tag.id– JOIN post ON tag_post.post_id = post.id– WHERE tag.tag = 'mysql';

• 多個簡單查詢

– SELECT * FROM tag WHERE tag = 'mysql';– SELECT * FROM tag_post WHERE tag_id = 123;– SELECT * FROM post WHERE post_id IN (123,456,789);

7

Page 8: My sql explain & select

一個複雜的查詢 VS 多個簡單查詢? (2/2)

• 分解的好處– 1. 提高指令在查詢暫存器中的命中率!– 2. 如果 table 很大,不需將 table 展開– 2. 減少 table 鎖定的競爭– 3. 可以在應用層 (application) ,進行 sql 單元的拆分,提高擴展性– 4. 減少重複查詢相同的資料– 5. 執行的方式類似 hash association ,在某些條件下將會有更好的

效率

• 分解的缺點– 1. 增加 sql 維護的複雜度– 2. table 不大或是關聯條件都是屬於 primary 或 index ,

較無使用需要8

Page 9: My sql explain & select

MySQL 查詢執行的基礎 – 查詢優化器

9

Page 10: My sql explain & select

mysql 優化器的一些限制 (1/3)

• 一個關聯式的查詢:– SELECT * – FROM sakila.film– WHERE film_id IN (– SELECT film_id FROM sakila.film_actor WHERE actor_id = 1– );

• 我們以為的執行方式:– Step1. SELECT film_id FROM sakila.film_actor WHERE actor_id = 1;– ANS : film_id = 1,2,3,4,5,6– Step2. SELECT * FROM sakila.film WHERE film_id IN (1,2,3,4,5,6);

10

Page 11: My sql explain & select

mysql 優化器的一些限制 (2/3)

• 一個關聯式的查詢:– SELECT * – FROM sakila.film– WHERE film_id IN (– SELECT film_id FROM sakila.film_actor WHERE actor_id = 1– );

• 實際上執行的方式:– SELECT * – FROM sakila.film– WHERE EXISTS (– SELECT * – FROM sakila.film_actor – WHERE actor_id = 1 AND film_actor.film_id = film.film_id– );

11

Page 12: My sql explain & select

mysql 優化器的一些限制 (3/3)

• 解決的方法 (1). 使用 INNER JOIN– SELECT film.* – FROM sakila.film– JOIN sakila.film_actor USING (film_id)– WHERE film.actor_id = 1;

• 解決的方法 (2). 使用 GROUP_CONCAT 作為 subquery 的 index– SELECT * – FROM sakila.film– WHERE film_id IN (– SELECT GROUP_CONCAT(film_id) – FROM sakila.film_actor WHERE actor_id = 1– );

12

Page 13: My sql explain & select

如何優化 MIN() & MAX() ?

• MIN() 查詢案例:

– SELECT MIN(actor_id) – FROM sakila.actor WHERE first_name = 'PENELOPE';

• 分析如下:

– 因為 first_name 不是 index ,那 mysql 所以會執行全資料表掃描– 如果是 where 條件是執行 primary key 的掃描,當然就會比較快!

因為 PK index 本身就已經排序好了!

13

Page 14: My sql explain & select

如何優化關連式查詢?

• 1. 確保 ON 或 USING 的子句內,使用的列 (column) 最好是 index– table-A & table-B 使用 column-C 做關聯,如果關聯的順序 B ->

A ,那這樣就只需要在 A 中建立 index 即可– 一般來說只需要在關聯順位第二個加上 index 即可

• 2. 確保 GROUP BY 或 ORDER BY 指令只牽扯到同一個資料表中的列 (column) , 這樣 mysql 才有可能會使用 index 來處理!

14

Page 15: My sql explain & select

如何優化子查詢 (subquery) ?

• 若無法使用 index , mysql 會採用臨時資料表 (tempo table) ,或是直接將檔案排序 (filesort)

• 我們在寫的時候盡量以使用 index 為目標 !

• Before– SELECT actor.first_name, actor.last_name, COUNT(*)– FROM sakila.film_actor– INNER JOIN sakila.actor USING(actor_id)– GROUP BY actor.first_name, actor.last_name;

• After ( 利用演員姓名和 ID 都屬於同一筆資料的特性! )– SELECT actor.first_name, actor.last_name, COUNT(*)– FROM sakila.film_actor– INNER JOIN sakila.actor USING(actor_id)– GROUP BY film_actor.actor_id;

15

Page 16: My sql explain & select

如何優化 LIMIT ? (1/2)

• 在 mysql 中, LIMIT 5000, 5 – SELECT film_id, description FROM sakila.film ORDER BY title LIMIT

5000, 5;– 需要掃描 5005 筆,但是只取 5 筆資料出來使用

• 再讀取下一批, LIMIT 5005, 5 – SELECT film_id, description FROM sakila.film ORDER BY title LIMIT

5005, 5;– 需要掃描 5010 筆,但是只取 5 筆資料出來使用

• 重複 10 回,執行的代價相當的高!

16

Page 17: My sql explain & select

如何優化 LIMIT ? (2/2)

• 如何處理?盡可能是用 index 去處理這種狀況!而不要讓 mysql 掃描整份資料表

• 亦可在第一次查詢的時候取得 film_id ,然後利用 film_id排除掉不需要掃描的 rows ,以此類推~– film_id = 5005– SELECT film_id, description

FROM sakila.film WHERE film_id > 5005 ORDER BY title LIMIT 5;

17

Page 18: My sql explain & select

如何優化 UNION ?

• 因為 UNION 一直以來都是以“暫存”的方式執行 SELECT查詢,所以很多依靠 index 的優化策略沒辦法很好的發揮作用

• 建議作法:是將 WHERE , LIMIT , ORDER BY 下推到 UNION 的各子查詢階段提前處理.

18

Page 19: My sql explain & select

MySQL Explain

• 1. Id• 2. select_type• 3. table• 4. type• 5. poddible_keys• 6. key• 7. key_len• 8. ref• 9. rows• 10. extra

19

Page 20: My sql explain & select

1. ID

• MySQL 執行的順序號碼, ID 依照大到小的的順序執• SELECT 如果有子查詢,子查詢的 ID號碼就會開始遞增

20

Page 21: My sql explain & select

2. Select_type

• (1) SIMPLE : 最簡單的 SELECT( 不使用 UNION 或子查询等 )• (2) PRIMARY : 最外層的 SELECT.• (3) UNION : UNION 中的第二個或是後面的 SELECT语句 . • (4) DEPENDENT UNION :

UNION 的第二個或後面 SELECT 的來源是子查詢• (5) UNION RESULT : UNION 的结果 .• (6) SUBQUERY : 子查詢中的第一個 SELECT.

– select * from t3 where id = (select id from t3 where id=3952602 ) ;

• (7) DEPENDENT SUBQUERY : 子查詢中的第一個 SELECT– select * from t3 where id IN (select id from t3 where id=3952602 ) ;

• (8) DERIVED : FROM 子句的子查詢 ( 暫存表 )

21

Page 22: My sql explain & select

3. table

• 顯示這一行的數據是處理哪張 table 的• 有時候看到的不是真實的 table 名字,看到的是 DERIVED X

( x 是一個數字,代表某一步驟 ID 的執行結果 )

22

Page 23: My sql explain & select

4. type

• 最好到最差的连接类型为 : • (1) system• (2) const• (3) eq_ref• (4) ref• (5) ref_or_null• (6) index_merge• (7) unique_subquery• (8) index_subquery• (9) range• (10) index• (11) ALL

23

Page 24: My sql explain & select

5.possible_keys

• possible_keys 列,裡面指出 MySQL 可以使用哪些 index ,就能在該table找到這些資料 (rows)。

24

Page 25: My sql explain & select

6. key

• 顯示 MySQL 實際上真正有使用到的 index ,如果沒有使用任何的index ,結果會為 NULL

25

Page 26: My sql explain & select

7. key_len

• key_len 顯示 MySQL 本次執行 key 的長度。• 如果項目 6. key 是 NULL ,則長度為 NULL。• 在不影響資料的正確性下,使用的 ken_len 長度越小越好。

26

Page 27: My sql explain & select

8. ref

• 顯示哪些欄位或是哪個常數與 key 一起成為 table 的查詢條件

27

Page 28: My sql explain & select

9. rows

• rows 顯示 MySQL 在執行的時候,在中 table 掃描的行數

28

Page 29: My sql explain & select

10. Extra (1/2)

• (1) Distinct :當 MySQL找到相關連的資料時,就不再搜尋。• (2) Not exists :

MySQL 優化 LEFT JOIN , 一旦找到符合的 LEFT JOIN 資料後,就不再搜尋。

• (3) Range checked for each Record : MySQL 無法找到理想的索引。此為最慢的使用索引。

• (4) Using filesort : 當出現這個值時,表示此 SELECT語法需要優化。 因為 MySQL 必須進行額外的步驟來進行資料掃描, 此情況會發生在針對不同的資料進行 ORDER BY 或是 GROUP BY

• (5) Using index : 返回的資料是從 index 中取得的資料,而不是從實際的 table 中返回, 當返回的資料都出現在索引中的資料時就會發生此情況。

• (6) Using temporary : 此為 MySQL 必須建立一個暫時的資料表 (Table) 來儲存結果。

29

Page 30: My sql explain & select

10. Extra (2/2)

• (7) Using where : 使用 WHERE語法中的欄位來取得結果。

• (8) eq_ref : MySQL 在關聯查詢時, 在查詢時使用主鍵 (primary key) 或唯一鍵 (unique) 的全部。

• (9) ref : 關聯查詢時使用了非唯一鍵或主鍵的 index 時。

• (10) range : 使用 index 取得一個範圍的結果。 例如:使用大於 > 或小於 < 查詢時發生。

• (11) index : 此為針對索引中的資料進行查詢。

• (12) ALL : 針對每一筆記錄進行完全掃描,此為最壞的情況,應該盡量避免。

30

Page 31: My sql explain & select

EXPLAIN:Extra = filesort

• 當無法使用 index產生排序結果的時候,mysql 就需要自行排序

• 如果資料量小在暫存區內 (Temporary)• 如果數據量大到無法在暫存區內處理,則需要用到 IO 讀取硬碟

• 無論是暫存或是硬碟, extra 一律顯示 filesort

31

Page 32: My sql explain & select

SHOW PROFILES & PROFILE

• SHOW PROFILE & SHOW PROFILES 可以檢視我們的 query 指令在執行過程中多種系統資源的消耗情況.

• 如 CPU、 IO、 IPC、 SWAP 等,以及發生的 PAGE FAULTS、 CONTEXT SWITCHE 等等.

32

Page 33: My sql explain & select

Profiling 參數

• Profiling 是一個存在於 MySQL session 中的一個參數值,控制 Profiling功能是否開啟 / 關閉.– 查詢 profiling參數狀態,指令: SELECT @@profiling;– 預設值為 0 關閉– 設定 1 開啟,指令: SET profiling = 1;

• 當開啟 Profiling 後, MySQL 將會自動紀錄所有執行的query歷史資訊.– MySQL預設保存的查詢歷史,筆數為 15– 查詢 profiling_history_size 目前的設定,指令:

SELECT @@profiling_history_size;– 設定歷史保存的上限 ( 最高限制為 100) ,指令:

SET profiling_history_size = 30;

33

Page 34: My sql explain & select

Profiles

• 開啟 Profiling 與設定好 Profiling_history_size 後,可以呼叫profiles 來顯示最新 N 件的查詢請求記錄– 指令: SHOW PROFILES;

• 顯示結果– Query_ID :查詢指令的流水號– Duration :查詢的花費時間– Query :查詢的 SQL語句

34

Page 35: My sql explain & select

Profile

• 開啟 Profiling 與設定好 Profiling_history_size 後,可以呼叫 profiles 來顯示最新 N 件的查詢請求記錄– 指令: SHOW PROFILE ALL FOR QUERY 8 ; 查詢 queryID=8 的 profile 資訊

35

指令 Profile 參數 queryID 參數 參數描述

SELECT PROFILE

ALL

FOR QUERY (n)

顯示所有 profile 資訊

BLOCK IO 顯示 BLOCK input & output 的次數

CONTEXT SWITCHES 顯示自動 &非自動的 context switches 的次數

CPU 顯示 CPU 使用量

IPC 顯示訊息送出與回覆的次數

MEMORY (X) 現在沒有實作

PAGE FAULTS 顯示主要與次要的分頁錯誤次數

SOURCE

SWAPS

Page 36: My sql explain & select

P

36

Page 37: My sql explain & select

範例:以 Xboard 為例 (Before-1/3)

• 案例:查詢群組 <音樂 > 中,分類為 <華語音樂 > 的 content– View : vw_page_content 是 content 內容露出格式的 sql view

• 執行時間: duration = '0.17545700’ sec• 取得筆數: 234

37

Page 38: My sql explain & select

範例:以 Xboard 為例 (Before-2/3)

• 案例:查詢群組 <音樂 > 中,分類為 <華語音樂 > 的 content– View : vw_page_content 是 content 內容露出格式的 sql view

• 執行時間: duration = '0.17545700’ sec• 取得筆數: 234

38

注意 subquery result 的size!

冗餘的指令!?

Page 39: My sql explain & select

範例:以 Xboard 為例 (Before-3/3)

• Explain 分析結果:

39

Page 40: My sql explain & select

範例:以 Xboard 為例 (After-1/2)

• 案例:查詢群組 <音樂 > 中,分類為 <華語音樂 > 的 content– View : vw_page_content 是 content 內容露出格式的 sql view

• 執行時間: duration = ‘0.00572175’ sec (之前是 0.17545700)• 取得筆數: 234

40

移除 group 指令

交換 subquuery 執行的順序較大的 table 往外搬

Page 41: My sql explain & select

範例:以 Xboard 為例 (After-2/2)

• Explain 分析結果:

41

Page 42: My sql explain & select

Conclusion

• 建立 table scheme 的階段,應訂定較有意義的 primary key

• SELECT 語句注意的事項:– 盡量將冗餘的指令移除– 查詢的條件盡量使用 primary , index ,避免大量掃描到 table 內的資料– 盡可能使用效率較高的 inner join 處理關聯的資料– 注意 subquery 的執行順序,

取得資料與掃瞄 table 盡量在最後要返回結果的時候再執行!– 注意 subquery 過程中 temporary table 的大小

• Explain 應注意的項目– Select_type – Type :避免出現大量的 ALL– Rows : rows 越大即代表掃瞄的筆數越多– Extra :盡力避免掉出現 ALL ,減少 Using temporary ,以及盡量讓 Using filesort 在 out result階段再執行

42

Page 43: My sql explain & select

Reference

• MySQL Explain– Select_type – Type :避免出現大量的 ALL– Rows : rows 越大即代表掃瞄的筆數越多– Extra :盡力避免掉出現 ALL ,減少 Using temporary ,以及盡量讓 Using filesort 在 out

result階段再執行

• MySQL Profiles– http://dev.mysql.com/doc/refman/5.7/en/show-profile.html– http://blog.longwin.com.tw/2008/10/mysql-query-profiler-cpu-ram-time-2008

/– http://bian5399.blog.51cto.com/3848702/842165– http://blog.csdn.net/dba_waterbin/article/details/12245891

43