狠狠撸

狠狠撸Share a Scribd company logo
MySQL 的 SELECT 優化與 EXPLAIN
Present by MingIn
1
Outline
? MySQL 查詢優化
? MySQL Explain
? MySQL Profiles
? Xboard 範例
? Conclusion
2
MySQL 查詢優化
? 目標:
– 了解MySQL如何執行查詢
– 了解查詢高低效率的原因何在
– 如何充分發揮MySQL的優勢,避開它的弱點
3
為什麼查詢的效能不佳?
? 典型效能低落案例
– 1. 查詢不必要的紀錄
– 2. 多表關聯查資料的時候(join or subqueries),返回全部rows資料
– 3. 總是取出全部的列資料
– 4. 一直重複查詢相同的資料數據
4
如何評估查詢的效能?
? 1. 指令回覆時間 = 服務執行時間 + 排隊等待時間
? 2. 掃描的行數&返回的行數:以 10:1 ~ 1:1 為佳
? 3. 掃描的行數&查詢的類型(explain:type & rows)
5
查詢速度由好到壞
? 1. where 條件使用在 primary key 上 (system)
? 2. where 條件使用在 index 上 (type:using index)
? 3. where 條件使用在一般資料上 (type:using where)
6
一個複雜的查詢 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
一個複雜的查詢 VS 多個簡單查詢?(2/2)
? 分解的好處
– 1. 提高指令在查詢暫存器中的命中率!
– 2. 如果table很大,不需將table展開
– 2. 減少table鎖定的競爭
– 3. 可以在應用層(application),進行sql單元的拆分,提高擴展性
– 4. 減少重複查詢相同的資料
– 5. 執行的方式類似 hash association,在某些條件下將會有更好的
效率
? 分解的缺點
– 1. 增加sql維護的複雜度
– 2. table 不大或是關聯條件都是屬於 primary 或 index,
較無使用需要
8
MySQL 查詢執行的基礎 – 查詢優化器
9
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
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
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
如何優化MIN() & MAX()?
? MIN()查詢案例:
– SELECT MIN(actor_id)
– FROM sakila.actor WHERE first_name = 'PENELOPE';
? 分析如下:
– 因為 first_name 不是 index,那mysql 所以會執行全資料表掃描
– 如果是where條件是執行primary key的掃描,當然就會比較快!
因為PK index 本身就已經排序好了!
13
如何優化關連式查詢?
? 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
如何優化子查詢(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
如何優化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
如何優化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
如何優化UNION?
? 因為 UNION 一直以來都是以“暫存”的方式執行SELECT查詢,
所以很多依靠 index 的優化策略沒辦法很好的發揮作用
? 建議作法:是將 WHERE,LIMIT,ORDER BY 下推到 UNION
的各子查詢階段提前處理.
18
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
1. ID
? MySQL執行的順序號碼,ID 依照大到小的的順序執
? SELECT 如果有子查詢,子查詢的ID號碼就會開始遞增
20
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
3. table
? 顯示這一行的數據是處理哪張table的
? 有時候看到的不是真實的table名字,看到的是 DERIVED X
( x 是一個數字,代表某一步驟ID的執行結果)
22
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
5.possible_keys
? possible_keys列,裡面指出MySQL可以使用哪些index,就能在該table
找到這些資料(rows)。
24
6. key
? 顯示 MySQL 實際上真正有使用到的 index,如果沒有使用任何的index,
結果會為 NULL
25
7. key_len
? key_len 顯示 MySQL 本次執行key的長度。
? 如果項目6. key是NULL,則長度為NULL。
? 在不影響資料的正確性下,使用的ken_len 長度越小越好。
26
8. ref
? 顯示哪些欄位或是哪個常數與key一起成為table的查詢條件
27
9. rows
? rows 顯示 MySQL在執行的時候,在中table掃描的行數
28
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
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
EXPLAIN:Extra = filesort
? 當無法使用index產生排序結果的時候,
mysql就需要自行排序
? 如果資料量小在暫存區內(Temporary)
? 如果數據量大到無法在暫存區內處理,
則需要用到IO讀取硬碟
? 無論是暫存或是硬碟,extra一律顯示 filesort
31
SHOW PROFILES & PROFILE
? SHOW PROFILE & SHOW PROFILES 可以檢視我們的 query 指
令在執行過程中多種系統資源的消耗情況.
? 如 CPU、IO、IPC、SWAP等,以及發生的 PAGE FAULTS、
CONTEXT SWITCHE等等.
32
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
Profiles
? 開啟Profiling與設定好Profiling_history_size後,可以呼叫
profiles來顯示最新N件的查詢請求記錄
– 指令:SHOW PROFILES;
? 顯示結果
– Query_ID:查詢指令的流水號
– Duration:查詢的花費時間
– Query:查詢的SQL語句
34
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
P
36
範例:以Xboard 為例 (Before-1/3)
? 案例:查詢群組<音樂>中,分類為<華語音樂>的content
– View : vw_page_content 是 content 內容露出格式的 sql view
? 執行時間:duration = '0.17545700’ sec
? 取得筆數:234
37
範例:以Xboard 為例 (Before-2/3)
? 案例:查詢群組<音樂>中,分類為<華語音樂>的content
– View : vw_page_content 是 content 內容露出格式的 sql view
? 執行時間:duration = '0.17545700’ sec
? 取得筆數:234
38
注意subquery result的size!
冗餘的指令!?
範例:以Xboard 為例 (Before-3/3)
? Explain 分析結果:
39
範例:以Xboard 為例 (After-1/2)
? 案例:查詢群組<音樂>中,分類為<華語音樂>的content
– View : vw_page_content 是 content 內容露出格式的 sql view
? 執行時間:duration = ‘0.00572175’ sec (之前是 0.17545700)
? 取得筆數:234
40
移除 group 指令
交換 subquuery執行的順序
較大的table 往外搬
範例:以Xboard 為例 (After-2/2)
? Explain 分析結果:
41
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
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

More Related Content

My sql explain & select

  • 1. MySQL 的 SELECT 優化與 EXPLAIN Present by MingIn 1
  • 2. Outline ? MySQL 查詢優化 ? MySQL Explain ? MySQL Profiles ? Xboard 範例 ? Conclusion 2
  • 3. MySQL 查詢優化 ? 目標: – 了解MySQL如何執行查詢 – 了解查詢高低效率的原因何在 – 如何充分發揮MySQL的優勢,避開它的弱點 3
  • 4. 為什麼查詢的效能不佳? ? 典型效能低落案例 – 1. 查詢不必要的紀錄 – 2. 多表關聯查資料的時候(join or subqueries),返回全部rows資料 – 3. 總是取出全部的列資料 – 4. 一直重複查詢相同的資料數據 4
  • 5. 如何評估查詢的效能? ? 1. 指令回覆時間 = 服務執行時間 + 排隊等待時間 ? 2. 掃描的行數&返回的行數:以 10:1 ~ 1:1 為佳 ? 3. 掃描的行數&查詢的類型(explain:type & rows) 5
  • 6. 查詢速度由好到壞 ? 1. where 條件使用在 primary key 上 (system) ? 2. where 條件使用在 index 上 (type:using index) ? 3. where 條件使用在一般資料上 (type:using where) 6
  • 7. 一個複雜的查詢 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
  • 8. 一個複雜的查詢 VS 多個簡單查詢?(2/2) ? 分解的好處 – 1. 提高指令在查詢暫存器中的命中率! – 2. 如果table很大,不需將table展開 – 2. 減少table鎖定的競爭 – 3. 可以在應用層(application),進行sql單元的拆分,提高擴展性 – 4. 減少重複查詢相同的資料 – 5. 執行的方式類似 hash association,在某些條件下將會有更好的 效率 ? 分解的缺點 – 1. 增加sql維護的複雜度 – 2. table 不大或是關聯條件都是屬於 primary 或 index, 較無使用需要 8
  • 10. 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
  • 11. 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
  • 12. 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
  • 13. 如何優化MIN() & MAX()? ? MIN()查詢案例: – SELECT MIN(actor_id) – FROM sakila.actor WHERE first_name = 'PENELOPE'; ? 分析如下: – 因為 first_name 不是 index,那mysql 所以會執行全資料表掃描 – 如果是where條件是執行primary key的掃描,當然就會比較快! 因為PK index 本身就已經排序好了! 13
  • 14. 如何優化關連式查詢? ? 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
  • 15. 如何優化子查詢(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
  • 16. 如何優化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
  • 17. 如何優化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
  • 18. 如何優化UNION? ? 因為 UNION 一直以來都是以“暫存”的方式執行SELECT查詢, 所以很多依靠 index 的優化策略沒辦法很好的發揮作用 ? 建議作法:是將 WHERE,LIMIT,ORDER BY 下推到 UNION 的各子查詢階段提前處理. 18
  • 19. 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
  • 20. 1. ID ? MySQL執行的順序號碼,ID 依照大到小的的順序執 ? SELECT 如果有子查詢,子查詢的ID號碼就會開始遞增 20
  • 21. 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
  • 22. 3. table ? 顯示這一行的數據是處理哪張table的 ? 有時候看到的不是真實的table名字,看到的是 DERIVED X ( x 是一個數字,代表某一步驟ID的執行結果) 22
  • 23. 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
  • 25. 6. key ? 顯示 MySQL 實際上真正有使用到的 index,如果沒有使用任何的index, 結果會為 NULL 25
  • 26. 7. key_len ? key_len 顯示 MySQL 本次執行key的長度。 ? 如果項目6. key是NULL,則長度為NULL。 ? 在不影響資料的正確性下,使用的ken_len 長度越小越好。 26
  • 28. 9. rows ? rows 顯示 MySQL在執行的時候,在中table掃描的行數 28
  • 29. 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
  • 30. 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
  • 31. EXPLAIN:Extra = filesort ? 當無法使用index產生排序結果的時候, mysql就需要自行排序 ? 如果資料量小在暫存區內(Temporary) ? 如果數據量大到無法在暫存區內處理, 則需要用到IO讀取硬碟 ? 無論是暫存或是硬碟,extra一律顯示 filesort 31
  • 32. SHOW PROFILES & PROFILE ? SHOW PROFILE & SHOW PROFILES 可以檢視我們的 query 指 令在執行過程中多種系統資源的消耗情況. ? 如 CPU、IO、IPC、SWAP等,以及發生的 PAGE FAULTS、 CONTEXT SWITCHE等等. 32
  • 33. 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
  • 34. Profiles ? 開啟Profiling與設定好Profiling_history_size後,可以呼叫 profiles來顯示最新N件的查詢請求記錄 – 指令:SHOW PROFILES; ? 顯示結果 – Query_ID:查詢指令的流水號 – Duration:查詢的花費時間 – Query:查詢的SQL語句 34
  • 35. 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
  • 36. P 36
  • 37. 範例:以Xboard 為例 (Before-1/3) ? 案例:查詢群組<音樂>中,分類為<華語音樂>的content – View : vw_page_content 是 content 內容露出格式的 sql view ? 執行時間:duration = '0.17545700’ sec ? 取得筆數:234 37
  • 38. 範例:以Xboard 為例 (Before-2/3) ? 案例:查詢群組<音樂>中,分類為<華語音樂>的content – View : vw_page_content 是 content 內容露出格式的 sql view ? 執行時間:duration = '0.17545700’ sec ? 取得筆數:234 38 注意subquery result的size! 冗餘的指令!?
  • 39. 範例:以Xboard 為例 (Before-3/3) ? Explain 分析結果: 39
  • 40. 範例:以Xboard 為例 (After-1/2) ? 案例:查詢群組<音樂>中,分類為<華語音樂>的content – View : vw_page_content 是 content 內容露出格式的 sql view ? 執行時間:duration = ‘0.00572175’ sec (之前是 0.17545700) ? 取得筆數:234 40 移除 group 指令 交換 subquuery執行的順序 較大的table 往外搬
  • 41. 範例:以Xboard 為例 (After-2/2) ? Explain 分析結果: 41
  • 42. 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
  • 43. 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