1. 程式人生 > >MySQL執行計劃復習

MySQL執行計劃復習

group 比例 nested lec 操作 對數 batch 防止 數據

MySQL執行計劃分析

Ⅰ、認識執行計劃的每個字段

(root@localhost) [(none)]> desc select 1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | NULL  | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | No tables used |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

1.1 id

  • 單純的join,id都是1,且從上到下
  • subquery、scala subquery都會使id遞增

1.2 select type

  • simple
    • 不使用union或者subquery的簡單query
    • 子查詢被優化器打開,失效了
  • primary
    • 使用union結合select時,第一個select type
    • subquery的query
  • union
    • 使用union結合select除了第一個select type為primary,其余為union(extra中union result是union去掉重復值的臨時表)
    • 5.7開始union all不會出現union result,因為不去重
  • subquery
    • 不是用在from後面的subquery
    • 和外部表無關聯
    • subquery(標量子查詢)執行計劃沒錯誤,不代表sql執行沒錯(不能超過1行數據,subquery return more than 1 row)
  • dependent subquery
    • 必須依附於外面的值
    • scala subquery(和外部有關系的標量子查詢)
    • exists
  • derived
    • from位置之後的subquery
    • derived是生成在內存或者臨時表空間中
    • 如果derived作驅動表時,要點是減少數據量
    • 當作被驅動表時產生auto_key索引,也是以減少數據量為目
    • 5.7中optimizer_switch=‘derived_merge=on‘可以把簡單subquery打開成join
    • derived_merge為on時被驅動表的連接條件要有索引,為off時被驅動表結果集要小
    • 5.7的derived_merge可能導致子查詢中order by失效
    • 5.7以下操作可以防止derived_merge
      • unin/union all
      • group by
      • distinct
      • 聚合函數
      • limit
      • @
  • materialized
    • 物化,5.7開始in會產生,葉會生成auto_key索引
    • in中使用hint QB_NAME,外層使用這個hint
      • select /+ semijoin(@sub MATERIALIZATION) / * from t_order t2 where t2.emp_no in (select /+ QB_NAME(sub) / t1.emp_no from dept_emp t1);

1.3 table

  • NULL
    • 表示不使用任何表
    • 使用dual
    • extra中出現select tables optimized away,多見於count操作
  • 表名或者表的別名
  • <derved + id><union + id>
    • 臨時表<>裏的數字是id列
    • tmp_table_size = max_heap_table_size適當調大

1.4 type

  • const
    • 使用primary key或者unique key取得一條數據
  • eq_ref
    • join,且滿足被驅動表的連接條件unique key或者primary key
  • ref
    • 對索引列做等號判斷
  • range
    • between in like > <
    • 和const的區別在於索引掃描範圍不一樣
  • index
    • 索引全掃描,比起表全掃描且order by的情情況,但是絕大部分情況下也是優化對象
    • 不能使用range,const,ref的情況下,且只查詢索引列,即不回表,使用索引進行排序或者聚合即省略排序
    • 索引(a,b),select a from xxx where b = ‘‘; 即聯合索引中前導列不在where條件中,且查詢列在索引中
    • 在聚合運算中group by後面的列在索引或者primary key中,且查詢列也在索引中
  • all
    • 全表掃描
    • 大表中查詢超過一半以上的值,效果更好
    • 索引失效
      • 無索引
      • 對索引列加工
      • 索引列隱式類型轉換
      • 對日期類型進行like ‘20xxx‘
      • 單列索引,對數字列進行like ‘30%‘

1.5 possible_keys

  • 列出可能用到的索引,對優化沒什麽幫助
  • 5.6之後開始支持auto_key
  • auto_key就是臨時創建索引,需要消耗一些內存和cpu,對tmp_table_size,max_heap_table_size依賴較大
  • mysql列大小超過767個字節,無法生成auto_key
  • convert(xxx,數據類型,字符集)

1.6 key

  • sql用到的索引

1.7 key_len

  • 顯示sql到底使用了多少索引

1.8 ref

  • 只有type是ref或者const才會出現內容,沒啥用,不用管

1.9 rows

  • MySQL優化器根據統計信息預估出來的值,不準

1.10 filter

  • 和rows一樣是預估值,非100的情況是extra有using where關鍵字,表示從存儲引擎中拿到數據後再加工的比例
  • 5.7開始該值比較準確

1.11 Extra

  • Distinct
    • MySQL在join過程中取出一行之後查詢另一個表時,碰到一行就停止,有點像exsits
    • 必須是join
    • distinct關鍵字
    • select列上只能含有驅動表的字段
    • 使用straight_join hint可以強制改變驅動表
  • select tables optimized away
    • 查詢中只有min、max的時候出現,有時候count貌似也會出現
    • 聯合主鍵,其中任一一個字段用等值查詢,查出另一個字段的min或max,且不能包含group by
  • Using filesort
    • order by, group by且沒使用索引
    • 8.0 group by不會出現
  • Using index
    • 只使用索引不回表就可以查到
    • 如果表對應的where條件選擇率不是很好,且一行長度很長,此時課考慮創建包含對應列的索引達到減少物理io的目的
    • 延遲join必須使用using index,否則無效
  • Using temporary
    • sql執行過程中存儲中間結果會使用tempoary table,但無法判斷在內存還是disk
    • order by,group by未使用索引
    • 執行計劃中的select type為derived
    • show swssion status like ‘%tmp%‘
    • max_heap_table_size和tmp_table_size(不一致時以小的為準)
  • Using where
    • 一般和filtered,rows一起看
    • 表示從存儲引擎中拿到數據再過濾
    • rows是存儲引擎中拿數據的預估值,filtered是再過濾的百分比
  • Using index condition
    • 必須是二級索引才有,且有索引後面部分無法使用時,回表次數很大,效果更好
    • optimizer_switch=‘index_condition_pushdown=on‘
  • Using MRR
    • optimizer_switdch=‘mrr_cost_based=0ff‘
    • 回表之前先排序,降低隨機io
  • Range checked for each record
    • type為all
    • 這是優化對象,緊接著用show warnings來定位問題
  • Using join buffer(Block Nested Loop)
    • optimizer_switch=‘block_nested_loop=on,batched_key_access=on‘
    • 被驅動表沒有索引且數據量較少的時候,一般這種情況也是優化對象

Ⅱ、獲取運行中SQL的執行計劃

desc for connection connection_id;

MySQL執行計劃復習