explain(解釋),在 Mysql 中 做爲一個關鍵詞,用來解釋 Mysql 是如何執行語句,能夠鏈接 select 、delete、insert、update 語句。sql
一般咱們使用 explain 鏈接 一條 select 語句,查看運行狀態,判斷是否須要優化。緩存
栗子:函數
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
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 |
type 列描述了表的 join 類型,如下以 查詢的最優到最差的排序列出了可能值:3d
以下的查詢,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 來處理 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;
下面的示例,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;
下面的示例,Mysql 可使用 ref_or_null join 來處理 ref_table::
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
形以下面的示例:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
形以下面的形式:
value IN (SELECT key_column FROM single_table WHERE some_expr)
例如:
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);
假設有以下的 sql:根據訂單日期 和 店員id 查詢 訂單信息(已建立了訂單日期的索引),查詢結果返回 18條記錄。
SELECT * FROM orders WHERE YEAR(o_orderdate) = 1992 AND MONTH(o_orderdate) = 4 AND o_clerk LIKE '%0223';
Explain 輸出執行計劃:
問題所在:
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萬左右。
爲 店員字段建立索引:
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。
建立以下索引:
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 |