【mysql】mysql 調優之 ——執行計劃 explain

1.what is explain(explain 是個什麼東東)

explain(解釋),在 Mysql 中 做爲一個關鍵詞,用來解釋 Mysql 是如何執行語句,能夠鏈接 select 、delete、insert、update 語句。sql

一般咱們使用 explain 鏈接 一條 select 語句,查看運行狀態,判斷是否須要優化。緩存

2.how to use explain(如何使用呢)

 

栗子:函數

explain select s.name,s.id,s.age,s.create_time from student s;

  

輸出:性能

  

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | s     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    7 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

  

官方:優化

EXPLAIN  [explain_type]  explainable_stmt


explain_type: {
    EXTENDED
  | PARTITIONS
  | FORMAT = format_name
}

explainable_stmt: {
    SELECT statement
  | DELETE statement
  | INSERT statement
  | REPLACE statement
  | UPDATE statement
}

 

輸出的列名:spa

  • id : select 標識符
  • select_type:select 類型

 

select_type 可選值 含義
SIMPLE 簡單的 select,沒有使用 UNION 或者 子查詢
PRIMARY 最外一層的 select
UNION UNION 中第二個或者後面的 select 語句
DEPENDENT UNION UNION 中第二個或者後面的 select 語句,依賴於外層的 select
UNION RESULT UNION 的結果
SUBQUERY 子查詢的第一個 select
DEPENDENT SUBQUERY 子查詢的第一個 select,取決於外層的 select
DERIVED 派生表
MATERIALIZED Materialized subquery
UNCACHEABLE SUBQUERY 沒法緩存結果的子查詢,必須爲外部查詢的每一行從新計算其結果
UNCACHEABLE UNION UNION 查詢中不可緩存的子查詢中的第二個或者後一個 select
  • table:輸出行對應的表
  • partitions:匹配的分區
  • type:join 類型
  • possible_keys:可選的索引,能夠經過 show index from tbl_name 查看錶有哪些索引。
  • key:實際選擇的索引
  • key_len:實際使用索引的長度
  • ref:與索引比較的列
  • rows:掃描行數的預估值
  • filtered:按表條件篩選的行的百分比
  • Extra:額外信息

 3.重點關注的列

3.1 type 列

type 列描述了表的 join 類型,如下以 查詢的最優到最差的排序列出了可能值:3d

  • system :當表只有一條數據(= system table)時,爲 system 類型,是 const 類型的 特例。

  

  • const:當表最多隻有一條數據相匹配時,爲 const 類型。由於只有一行,因此優化器的其他部分能夠將此行列中的值視爲常量(constant)。const表很是快,由於它們只讀一次。在使用 主鍵 或者 惟一索引 和常量比較時,即爲 const 類型。

以下的查詢,tbl_name 能夠被用做 const 表:code

SELECT * FROM tbl_name WHERE primary_key=1;

SELECT * FROM tbl_name
  WHERE primary_key_part1=1 AND primary_key_part2=2;

  

栗子:orm

explain select s.* from student s where s.id = 1

輸出:blog

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | s     | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+

  

  • eq_ref:一般出如今多表 join 查詢,而且 關聯的字段是 主鍵 或者 惟一非空索引,即後表 只能匹配一條數據。

下面的示例,可使用 eq_ref join  來處理 ref_table:

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

  

  • ref:一般出如今多表 join 查詢,關聯使用了 最左前綴原則的索引 或者 關聯的是非主鍵 或者 非 惟一索引(也就是說,join 不能根據索引選擇 單行數據)

下面的示例,Mysql 可使用 ref join 來處理  ref_table:

SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

  

  • fulltext:使用全文索引執行 join
  • ref_or_null:在 ref 的基礎上 , 另外還搜索了包含空值的行

下面的示例,Mysql 可使用 ref_or_null join 來處理  ref_table::

SELECT * FROM ref_table
  WHERE key_column=expr OR key_column IS NULL;

  

  • index_merge: 合併索引優化
  • unique_subquery:子查詢返回惟一主鍵。

形以下面的示例:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

  

  • index_subquery:和 unique_subquery 相似,只不過在子查詢中使用非惟一索引

形以下面的形式:

value IN (SELECT key_column FROM single_table WHERE some_expr)

  

  • range:當 索引和常量 使用 諸如=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN()  進行比較時 ,可使用 range.

例如:

SELECT * FROM tbl_name
  WHERE key_column = 10;

SELECT * FROM tbl_name
  WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name
  WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name
  WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

  

  • index:和 all 相似 ,只不過 掃描的是 索引樹
  • all:全表掃描,能夠經過增長 索引避免 全表掃描

3.2 keys 列:真正使用的索引

3.3 rows 列:掃描的記錄數

 4.使用 explain 提高查詢性能案例分析

假設有以下的 sql:根據訂單日期 和 店員id 查詢 訂單信息(已建立了訂單日期的索引),查詢結果返回 18條記錄。

  SELECT * FROM orders
  WHERE YEAR(o_orderdate) = 1992 AND MONTH(o_orderdate) = 4
  AND o_clerk LIKE '%0223';

  

Explain 輸出執行計劃:

問題所在:

  • 根據 type 爲 ALL , 查詢進行了全表掃描,被掃描的記錄 rows 爲  150萬。
  • possible_keys 和 ky 均爲空 ,訂單日期索引徹底失效,緣由在於被索引的字段使用了處理函數致使索引失效

4.1.修改sql 保證 訂單日期索引正常,

 SELECT * FROM orders
  WHERE o_orderdate BETWEEN '1992-04-01' AND '1992-04-30'
  AND o_clerk LIKE '%0223';

  

從新使用 Explain 查看 執行計劃:

發現:type 由 ALL 變爲 range ,訂單日期索引得以利用,被掃描的記錄由 15萬 降爲 3.3萬左右。

4.2.另外一個優化點在 店員字段的過濾

爲 店員字段建立索引:

CREATE INDEX i_o_clerk ON orders(o_clerk);

  

再次輸出執行計劃:

發現:基本上並無什麼變化,新建的索引沒有被利用,緣由在於 該字段是 模糊查詢,過濾指定後綴的 店員信息。可是索引對於後綴過濾會失效(儘管索引對於前綴有效果)。

修改sql,全量過濾店員字段:

SELECT * FROM orders
WHERE o_orderdate BETWEEN '1992-04-01' AND '1992-04-30'
AND o_clerk LIKE 'Clerk#000000223';

  

再次輸出執行計劃:

發現:可用索引增長,真正使用的索引變爲 店員字段上的索引,被掃描的行由 3.3萬降爲 1546。

4.3.對於多條件查詢,能夠考慮使用組合索引

建立以下索引:

CREATE INDEX io_clerk_date ON orders(o_clerk, o_orderdate)

  ** :這裏將 o_clerk 放在 o_orderdate 以前,由於 o_orderdate 使用了 範圍,更優的放在前面。

再次輸出執行計劃:

發現:使用了組合索引,被掃描記錄即爲輸出的18條記錄。效率已最優化。

 

屢次優化的總結:

Type Possible keys Key Rows Scanned Duration (seconds) Extra info Rows returned
all NULL NULL 1.50M 1.201 Using where 18
range i_o_orderdate i_o_orderdate 32642 0.281 Using index condition; Using where 18
range i_o_orderdate, i_o_clerk i_o_clerk 1546 0.234 Using index condition; Using where 18
range i_o_orderdate, i_o_clerk, i_o_clerk_date i_o_clerk_date 18 0.234 Using index condition 18
相關文章
相關標籤/搜索