mysql調優之——執行計劃explain

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

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

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

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

栗子:bash

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
}
複製代碼

輸出的列名:ui

  • id : select 標識符
  • select_type: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 類型,如下以 查詢的最優到最差的排序列出了可能值:spa

  • system :當表只有一條數據(= system table)時,爲 system 類型,是 const 類型的 特例。
  • const:當表最多隻有一條數據相匹配時,爲 const 類型。由於只有一行,因此優化器的其他部分能夠將此行列中的值視爲常量(constant)。const表很是快,由於它們只讀一次。在使用 主鍵 或者 惟一索引 和常量比較時,即爲 const 類型。 以下的查詢,tbl_name 能夠被用做 const 表:
SELECT * FROM tbl_name WHERE primary_key=1;

SELECT * FROM tbl_name
  WHERE primary_key_part1=1 AND primary_key_part2=2;
複製代碼

栗子:code

explain select s.* from student s where s.id = 1
複製代碼

輸出:orm

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 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

歡迎關注 編程那點事兒,隨時隨地,想學就學~

相關文章
相關標籤/搜索