1. 程式人生 > >MySQL 效能優化——「Explain 分析實踐」

MySQL 效能優化——「Explain 分析實踐」

DESC、DESCRIBE和EXPLAIN這三個關鍵字都是我們常用的,但是使用場景不同。從MySQL解析器的角度而言,他們的實際用法是一致的。
即實際使用過程中 DESC 等價於 DESCRIBE 等價於 EXPLAIN 。我們常常用於以下兩種場景:

  1. 查看錶結構資訊
  2. 檢視SQL語句執行計劃

資料準備

建立兩張資料表,用於後續的測試呼叫。

CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `name` varchar(50) NOT NULL COMMENT '部門名稱'
, `depart_desc` varchar(50) DEFAULT NULL COMMENT '描述', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ---------------------------- -- Records of department -- ---------------------------- INSERT INTO `department` VALUES ('1', 'IT部', '程式猿'); INSERT INTO `department` VALUES
('2', '人事部', '很多美女');
INSERT INTO `department` VALUES ('3', '施工部', '糙漢子'); INSERT INTO `department` VALUES ('4', '財務部', '千萬別惹他們!'); INSERT INTO `department` VALUES ('5', '行政部', '生活大管家'); -- ---------------------------- -- Table structure for user -- ---------------------------- CREATE TABLE `user`
( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `age` int(11) DEFAULT NULL, `depart_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `user_index_1` (`name`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('2', 'Jack', '20', '1'); INSERT INTO `user` VALUES ('3', 'Mike', '25', '1'); INSERT INTO `user` VALUES ('4', 'Lucy', '22', '2'); INSERT INTO `user` VALUES ('5', 'Mircle', '30', '3'); INSERT INTO `user` VALUES ('6', 'Josn', '45', '4'); INSERT INTO `user` VALUES ('7', 'Sgodon', '30', '5');

查看錶結構資訊

1. 執行語法

{EXPLAIN | DESCRIBE | DESC}
    tbl_name [col_name | wild]

2. 呼叫例項


mysql> DESC user;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| name      | varchar(50) | NO   | MUL | NULL    |                |
| age       | int(11)     | YES  |     | NULL    |                |
| depart_id | int(11)     | YES  |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
4 rows in set (0.02 sec)
-----------------------------------------------------------------
mysql> EXPLAIN user;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| name      | varchar(50) | NO   | MUL | NULL    |                |
| age       | int(11)     | YES  |     | NULL    |                |
| depart_id | int(11)     | YES  |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
4 rows in set (0.02 sec)

使用EXPLAIN和DESC的效果是一樣的,相類似的語法有 SHOW CREATE TABLE.

檢視SQL語句執行計劃

1.執行語法

{EXPLAIN | DESCRIBE | DESC}
    [explain_type]
    {explainable_stmt | FOR CONNECTION connection_id}

explain_type: {
    EXTENDED
  | PARTITIONS
  | FORMAT = format_name
}

format_name: {
    TRADITIONAL
  | JSON
}

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

2.呼叫示例

mysql> EXPLAIN SELECT * FROM user WHERE id = 4 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
1 row in set (0.00 sec)

#試一下用法-EXTENDED:多了一列 filtered
mysql> EXPLAIN EXTENDED SELECT * FROM user WHERE id= 4 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

#試一下用法-PARTITIONS:多了一列partitions
mysql> EXPLAIN PARTITIONS SELECT * FROM user WHERE id=4 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
   partitions: NULL
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
1 row in set (0.00 sec)

#試一下用法-FORMAT = JSON:預設就為Traditional
mysql> EXPLAIN FORMAT = JSON SELECT id FROM user WHERE id = 4 \G
*************************** 1. row ***************************
EXPLAIN: {
  "query_block": {
    "select_id": 1,
    "table": {
      "table_name": "user",
      "access_type": "const",
      "possible_keys": [
        "PRIMARY"
      ],
      "key": "PRIMARY",
      "used_key_parts": [
        "id"
      ],
      "key_length": "4",
      "ref": [
        "const"
      ],
      "rows": 1,
      "filtered": 100,
      "using_index": true
    }
  }
}

3.EXPLAIN輸出格式

mysql> EXPLAIN SELECT * FROM user WHERE id = 4 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
1 row in set (0.00 sec)
  1. id:SELECT的唯一標識,這是查詢中SELECT的序號,唯一。
  2. select_type:查詢型別
  3. table:查詢的表
  4. partitions:查詢呼叫到的分割槽資訊
  5. type:Join型別
  6. possible_keys:指示了MySQL可以選擇的索引,但是有可能不會使用
  7. key:MySQL真正使用的索引
  8. key_len:MySQL決定用的索引的長度,和key對應
  9. ref:將哪些列或常量與key列中命名的索引進行比較
  10. rows:執行查詢需要掃描的行數,預估值
  11. filtered:將被表條件過濾掉資料的百分比的預估值。
  12. Extra:額外資訊

select_type

  • SIMPLE:表示此查詢不包含 UNION 查詢或子查詢
  • PRIMARY: 表示此查詢是最外層的查詢
  • UNION:表示此查詢是 UNION 的第二或隨後的查詢
  • DEPENDENT UNION: UNION 中的第二個或後面的查詢語句, 取決於外面的查詢
  • UNION RESULT: UNION 的結果
  • SUBQUERY:子查詢中的第一個 SELECT
  • DEPENDENT SUBQUERY: 子查詢中的第一個 SELECT, 取決於外面的查詢 即子查詢依賴於外層查詢的結果

大部分的查詢都是SIMPLE,沒有子查詢和UNION連線。我們試一下 子查詢和UNION

#使用子查詢輸出結果如下:
mysql> EXPLAIN SELECT name,age FROM user WHERE depart_id = (SELECT id FROM department WHERE name='人事部門')\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: user
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
        Extra: Using where
*************************** 2. row ***************************
           id: 2
  select_type: SUBQUERY
        table: department
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5
        Extra: Using where
2 rows in set (0.00 sec)
----------------------------------------------------------------------------
#使用Union查詢輸出結果如下:
#union<1,2> 和使用union語句是相對應的,1、2指的是查詢ID的序號
mysql> EXPLAIN SELECT name,age FROM user WHERE depart_id = 1 UNION SELECT name,age FROM user WHERE depart_id=2 \G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: user
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
        Extra: Using where
*************************** 2. row ***************************
           id: 2
  select_type: UNION
        table: user
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
        Extra: Using where
*************************** 3. row ***************************
           id: NULL
  select_type: UNION RESULT
        table: <union1,2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Using temporary
3 rows in set (0.00 sec)

table

有以下幾種形式:
-

mysql> EXPLAIN SELECT u.name,u.age FROM (SELECT * FROM user WHERE depart_id=2) u \G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
        Extra: NULL
*************************** 2. row ***************************
           id: 2
  select_type: DERIVED
        table: user
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
        Extra: Using where
2 rows in set (0.00 sec)

type

  • system: 表中只有一條資料. 這個型別是特殊的 const 型別。
# full_3 只有一條資料,但是呼叫全表查詢時還是使用的ALL  

mysql> SELECT * FROM full_3;
+----+------+------+-------------+
| id | pkid | name | create_time |
+----+------+------+-------------+
|  1 |    1 | 3    | NULL        |
+----+------+------+-------------+
1 row in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM full_3 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: full_3
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
        Extra: NULL
1 row in set (0.00 sec)

# 通過這樣的子查詢時可以的
mysql> EXPLAIN SELECT d.* FROM (SELECT * FROM full_3 fu WHERE fu.id=1) d \G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: system
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
        Extra: NULL
*************************** 2. row ***************************
           id: 2
  select_type: DERIVED
        table: fu
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
2 rows in set (0.00 sec)

  • const: 針對主鍵或唯一索引的等值查詢掃描, 最多隻返回一行資料. const 查詢速度非常快, 因為它僅僅讀取一次即可。
mysql> EXPLAIN SELECT * FROM user WHERE id =3 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
1 row in set (0.00 sec)
  • eq_ref: 此型別通常出現在多表的 join 查詢, 表示對於前表的每一個結果, 都只能匹配到後表的一行結果. 並且查詢的比較操作通常是 =, 查詢效率較高.

  • ref: 此型別通常出現在多表的 join 查詢, 針對於非唯一或非主鍵索引, 或者是使用了 最左字首 規則索引的查詢.
    例如下面這個例子中, 就使用到了 ref 型別的查詢:

mysql> EXPLAIN SELECT name FROM user WHERE name = 'Jack' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: ref
possible_keys: user_index_1
          key: user_index_1
      key_len: 152
          ref: const
         rows: 1
        Extra: Using where; Using index
1 row in set (0.00 sec)
  • range: 表示使用索引範圍查詢, 通過索引欄位範圍獲取表中部分資料記錄. 這個型別通常出現在 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中.
    當 type 是 range 時, 那麼 EXPLAIN 輸出的 ref 欄位為 NULL, 並且 key_len 欄位是此次查詢中使用到的索引的最長的那個.
mysql> EXPLAIN SELECT * FROM user WHERE name LIKE 'Jack'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: range
possible_keys: user_index_1
          key: user_index_1
      key_len: 152
          ref: NULL
         rows: 1
        Extra: Using index condition
1 row in set (0.00 sec)
  • index: 表示全索引掃描(full index scan), 和 ALL 型別類似, 只不過 ALL 型別是全表掃描, 而 index 型別則僅僅掃描所有的索引, 而不掃描資料.
    index 型別通常出現在: 所要查詢的資料直接在索引樹中就可以獲取到, 而不需要掃描資料. 當是這種情況時, Extra 欄位 會顯示 Using index.
#如果用=就變成REF
mysql> EXPLAIN SELECT name FROM user WHERE name != 'Jack' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: index
possible_keys: user_index_1
          key: user_index_1
      key_len: 152
          ref: NULL
         rows: 6
        Extra: Using where; Using index
1 row in set (0.00 sec)
  • ALL: 表示全表掃描, 這個型別的查詢是效能最差的查詢之一. 通常來說, 我們的查詢不應該出現 ALL 型別的查詢, 因為這樣的查詢在資料量大的情況下, 對資料庫的效能是巨大的災難. 如一個查詢是 ALL 型別查詢, 那麼一般來說可以對相應的欄位新增索引來避免.
    下面是一個全表掃描的例子, 可以看到, 在全表掃描時, possible_keys 和 key 欄位都是 NULL, 表示沒有使用到索引, 並且 rows 十分巨大, 因此整個查詢效率是十分低下的.
mysql> EXPLAIN SELECT name FROM user WHERE age = 1 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
        Extra: Using where
1 row in set (0.00 sec)

possible_keys

possibel_keys表示MySQL在查詢過程中能夠用到的索引,但是不一定會使用。具體使用的索引,由Key決定。

key

key這一列是MySQL真正使用的索引。

ken_len

key_len 表示查詢優化器使用了索引的位元組數. 這個欄位可以評估組合索引是否完全被使用, 或只有最左部分欄位被使用到。

rows

rows列顯示MySQL執行查詢預計會覆蓋的行數,這個值越小越好。

Extra

有很多額外資訊,舉三個例子簡單說明下。

Impossible WHERE noticed after reading const tables

預示著Where列有邏輯問題,可能一直是FALSE,無法獲取資料。例如:

mysql> EXPLAIN SELECT * FROM user WHERE id >3 AND id<2 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Impossible WHERE noticed after reading const tables
1 row in set (0.00 sec)

Using filesort

查詢結果進行排序,例如:

mysql> EXPLAIN SELECT * FROM user WHERE id >3 ORDER By age \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 4
        Extra: Using where; Using filesort
1 row in set (0.00 sec)

Using index

覆蓋索引,從輔助索引中就能夠得到需要的資料,而不需要查詢聚集索引中的記錄。

mysql> EXPLAIN SELECT name FROM user WHERE name LIKE 'I%' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: range
possible_keys: user_index_1
          key: user_index_1
      key_len: 152
          ref: NULL
         rows: 1
        Extra: Using where; Using index
1 row in set (0.00 sec)

相關推薦

MySQL 效能優化——Explain 分析實踐

DESC、DESCRIBE和EXPLAIN這三個關鍵字都是我們常用的,但是使用場景不同。從MySQL解析器的角度而言,他們的實際用法是一致的。 即實際使用過程中 DESC 等價於 DESCRIBE 等價於 EXPLAIN 。我們常常用於以下兩種場景:

MySQL 效能優化神器 Explain 使用分析

簡介 MySQL 提供了一個 EXPLAIN 命令, 它可以對 SELECT 語句進行分析, 並輸出 SELECT 執行的詳細資訊, 以供開發人員針對性優化.EXPLAIN 命令用法十分簡單, 在 SELECT 語句前加上 Explain 就可以了, 例如: EXPLAIN SELECT * from use

mysql效能優化-慢查詢分析優化索引和配置 (慢查詢日誌,explain,profile)

一、優化概述 二、查詢與索引優化分析 1效能瓶頸定位 Show命令 慢查詢日誌 explain分析查詢 profiling分析查詢 2索引及查詢優化 三、配置優化 1)      max_connections 2)      back_log 3)      interactive_timeout 4)

mysql效能優化-慢查詢分析優化索引和配置

目錄 一、優化概述 二、查詢與索引優化分析 1效能瓶頸定位 Show命令 慢查詢日誌 explain分析查詢 profiling分析查詢 2索引及查詢優化 三、配置優化 1)      max_connections 2)      back_lo

MySQL資料庫優化——通過explain查詢分析SQL的執行計劃

使用explain查詢SQL的執行計劃 SQL的執行計劃側面反映出了SQL的執行效率,具體執行方式如下所示: 在執行的SQL前面加上explain關鍵詞即可;   2、每個欄位的說明: 1)、id列數字越大越先執行,如果說數字一樣大,那麼就從上往下依次執行,id列

[重要] -- MySQL效能優化的21個最佳實踐mysql使用索引

今天,資料庫的操作越來越成為整個應用的效能瓶頸了,這點對於Web應用尤其明顯。關於資料庫的效能,這並不只是DBA才需要擔心的事,而這更是我 們程式設計師需要去關注的事情。當我們去設計資料庫表結構,對操作資料庫時(尤其是查表時的SQL語句),我們都需要注意資料操作的效

MySQL效能優化的21個最佳實踐mysql使用索引

今天,資料庫的操作越來越成為整個應用的效能瓶頸了,這點對於Web應用尤其明顯。關於資料庫的效能,這並不只是DBA才需要擔心的事,而這更是我 們程式設計師需要去關注的事情。當我們去設計資料庫表結構,對操作資料庫時(尤其是查表時的SQL語句),我們都需要注意資料操作的效能。這裡,我們不會講過 多的SQL語句的優

mysql效能優化------explain詳解

1.explain作用 explain語句提供了MySQL如何執行語句的資訊。解釋選擇、刪除、插入、替換和更新語句如何工作。 2.如何使用 explain your command; se

Mysql 效能優化Explain詳解

explain 功能我們在日常使用中,使用慢查詢找到執行時間比較久的查詢,然後使用SHOW STATUS、SHOW PROFILE、和explain做單條語句的分析。使用explain關鍵字可以模擬優化器執行sql查詢語句,從而知道Mysql是如何處理你的sql語句的。分析你的查詢語句或者表結構的效能瓶頸。

MySQL效能優化MySQL索引優化,order by優化explain優化

前言 今天我們來講講如何優化MySQL的效能,主要從索引方面優化。下期文章講講MySQL慢查詢日誌,我們是依據慢查詢日誌來判斷哪條SQL語句有問題,然後在進行優化,敬請期待MySQL慢查詢日誌篇 建表 // 建表CREATE TABLE IF NOT EXI

MySQL查詢優化explain的深入解析

extra lin sub const query gin alt com nec 本篇文章是對MySQL查詢優化中的explain進行了詳細的分析介紹,需要的朋友參考下 在分析查詢性能時,考慮EXPLAIN關鍵字同樣很管用。EXPLAIN關鍵字一般放在SELECT查

MySQL(三) —— MySQL效能優化之 索引優化

MySQL索引優化 如何選擇合適的列建立索引? 在where從句、group by 從句、order by 從句、on 從句中出現的列 索引欄位越小越好 離散度大的列放在聯合索引的前面 如何判斷列的離散度? 去重查詢看列的唯一值,唯一值越多則離散度越大。 mysql&

MySQL(二) —— MySQL效能優化之 SQL語句優化

          SQL語句優化   MySQL優化的目的   1、避免出現頁面訪問錯誤:或由於資料庫連線超時 timeout 產生頁面5xx錯誤;或由於慢查詢造成頁面無法載入;或由於阻        塞造成資料無法提交;

MySQL (一) —— MySQL效能優化之 慢查詢日誌

                        &nbs

MySQL效能優化(六):分割槽

一: 分割槽簡介 分割槽是根據一定的規則,資料庫把一個表分解成多個更小的、更容易管理的部分。就訪問資料庫應用而言,邏輯上就只有一個表或者一個索引,但實際上這個表可能有N個物理分割槽物件組成,每個分割槽都是一個獨立的物件,可以獨立處理,可以作為表的一部分進行處理。分割槽對應用來說是完全

Mysql效能優化實戰

1、索引設計規範 常見索引列建議: SELECT、UPDATE、DELETE語句的WHERE從句中的列 包含在ORDER BY、GROUP BY、DISTINCT中的欄位,建議聯合索引 多表JOIN的關聯列 索引列的順序: 區分度最高的列放在聯合索引的最左側 儘量把欄位長度

mysql效能優化之建立高效能索引

索引對效能的優化十分重要,是對查詢優化最有效的手段。 一、索引的型別 索引是在儲存引擎層而不是服務層實現的。不同儲存引擎的索引工作方式不一樣。 1、B-Tree索引 它使用的是B-Tree資料結構來儲存資料。b-tree索引能夠加快訪問資料的速度,因為儲存引擎不在需要進行全表掃描

Mysql效能優化之資料型別優化

一、選擇正確的資料型別對於獲得高效能至關重要 1.1更小的通常更好 佔用更少的磁碟、記憶體和CPU快取 1.2儘量避免null 如果查詢中包含可為null的列,對Mysql來說更難優化,因為可為null的列使得索引、索引統計和值都更復雜。會使用更多的儲存空間. 2、整數和實數

從頭開始學MySQL-------效能優化

1.使用LIKE關鍵字可能觸發不了索引         首先執行下面的SQL,準備一些資料。 DROP TABLE IF EXISTS t_student; CREATE TABLE `t_student` ( `id` int(11) NO

資料庫Mysql效能優化

一、影響mysql效能的因素 sql語句查詢速度 伺服器硬體 網絡卡流量 磁碟IO 二、優化mysql的效能方法 優化sql語句,索引 使用快取,把經常使用的資料放到快取中,能節省磁碟IO 優化硬體,使用SSD硬碟 主從