搜尋
首頁資料庫mysql教程MySQL 效能最佳化--Explain 使用介紹


簡介

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

EXPLAIN SELECT * from user_info WHERE  id < 300;

準備

為了接下來方便示範EXPLAIN 的使用, 首先我們需要建立兩個測試用的表, 並添加對應的資料:

CREATE TABLE `user_info` (
  `id`   BIGINT(20)  NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) NOT NULL DEFAULT &#39;&#39;,
  `age`  INT(11)              DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name_index` (`name`)
)
  ENGINE = InnoDB
  DEFAULT CHARSET = utf8

INSERT INTO user_info (name, age) VALUES (&#39;xys&#39;, 20);
INSERT INTO user_info (name, age) VALUES (&#39;a&#39;, 21);
INSERT INTO user_info (name, age) VALUES (&#39;b&#39;, 23);
INSERT INTO user_info (name, age) VALUES (&#39;c&#39;, 50);
INSERT INTO user_info (name, age) VALUES (&#39;d&#39;, 15);
INSERT INTO user_info (name, age) VALUES (&#39;e&#39;, 20);
INSERT INTO user_info (name, age) VALUES (&#39;f&#39;, 21);
INSERT INTO user_info (name, age) VALUES (&#39;g&#39;, 23);
INSERT INTO user_info (name, age) VALUES (&#39;h&#39;, 50);
INSERT INTO user_info (name, age) VALUES (&#39;i&#39;, 15);
CREATE TABLE `order_info` (
  `id`           BIGINT(20)  NOT NULL AUTO_INCREMENT,
  `user_id`      BIGINT(20)           DEFAULT NULL,
  `product_name` VARCHAR(50) NOT NULL DEFAULT &#39;&#39;,
  `productor`    VARCHAR(30)          DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`)
)
  ENGINE = InnoDB
  DEFAULT CHARSET = utf8

INSERT INTO order_info (user_id, product_name, productor) VALUES (1, &#39;p1&#39;, &#39;WHH&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (1, &#39;p2&#39;, &#39;WL&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (1, &#39;p1&#39;, &#39;DX&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (2, &#39;p1&#39;, &#39;WHH&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (2, &#39;p5&#39;, &#39;WL&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (3, &#39;p3&#39;, &#39;MA&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (4, &#39;p1&#39;, &#39;WHH&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (6, &#39;p1&#39;, &#39;WHH&#39;);
INSERT INTO order_info (user_id, product_name, productor) VALUES (9, &#39;p8&#39;, &#39;TE&#39;);

EXPLAIN 輸出格式

EXPLAIN 指令的輸出內容大致如下:

<pre class='brush:php;toolbar:false;'>mysql&gt; explain select * from user_info where id = 2\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: user_info partitions: NULL type: const possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)</pre>

各列的意義如下:

  • id: SELECT 查詢的識別碼. 每個SELECT 都會自動分配一個唯一的識別碼.

  • select_type : SELECT 查詢的類型.

  • table: 查詢的是哪個表格

  • ##partitions: 符合的分區

  • #type: join 類型

  • possible_keys: 此查詢中可能選取的索引

  • ##key: 此查詢中確切使用到的索引.
  • ref: 哪個欄位或常數與key 一起被使用
  • rows: 顯示此查詢一共掃描了多少行.這是一個估計值.
  • filtered: 表示此查詢條件所過濾的資料的百分比
  • extra: 額外的資訊
  • 接下來我們來重點看一下比較重要的幾個字段.

select_type

select_type

表示了查詢的類型, 它的常用取值有:

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

了, 例如當我們的查詢沒有子查詢, 也沒有UNION 查詢時, 那麼通常就是SIMPLE 類型, 例如:<pre class='brush:php;toolbar:false;'>mysql&gt; explain select * from user_info where id = 2\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: user_info partitions: NULL type: const possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)</pre>如果我們使用了UNION 查詢, 那麼EXPLAIN 輸出的結果類似如下:

mysql> EXPLAIN (SELECT * FROM user_info  WHERE id IN (1, 2, 3))
    -> UNION
    -> (SELECT * FROM user_info WHERE id IN (3, 4, 5));
+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+
| id | select_type  | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra           |
+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+
|  1 | PRIMARY      | user_info  | NULL       | range | PRIMARY       | PRIMARY | 8       | NULL |    3 |   100.00 | Using where     |
|  2 | UNION        | user_info  | NULL       | range | PRIMARY       | PRIMARY | 8       | NULL |    3 |   100.00 | Using where     |
| NULL | UNION RESULT | <union1,2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL | NULL |     NULL | Using temporary |
+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)

table

表示查詢涉及的表或衍生表

#type

type

欄位比較重要, 它提供了判斷查詢是否高效的重要依據依據. 通過type 字段, 我們判斷此次查詢是全表掃描索引掃描 等.type 常用型別

type 常用的取值有:

##system : 表中只有一條資料. 這個型別是特殊的
    const
  • 類型.

    #const: 針對主鍵或唯一索引的等值查詢掃描, 最多只回傳一行資料. const 查詢速度非常快, 因為它僅僅讀取一次即可.
  • 例如下面的這個查詢, 它使用了主鍵索引, 因此
  • type

    就是
    const 類型的.

    mysql> explain select * from user_info where id = 2\G
    *************************** 1. row ***************************
            id: 1
    select_type: SIMPLE
         table: user_info
    partitions: NULL
          type: const
    possible_keys: PRIMARY
           key: PRIMARY
       key_len: 8
           ref: const
          rows: 1
      filtered: 100.00
         Extra: NULL
    1 row in set, 1 warning (0.00 sec)

    eq_ref: 此類型通常出現在多表的join 查詢,  表示對於前表的每一個結果, 都只能匹配到後表的一行結果. 並且查詢的比較操作通常是
  • =
  • , 查詢效率較高. 例如:

    mysql> EXPLAIN SELECT * FROM user_info, order_info WHERE user_info.id = order_info.user_id\G
    *************************** 1. row ***************************
            id: 1
    select_type: SIMPLE
         table: order_info
    partitions: NULL
          type: index
    possible_keys: user_product_detail_index
           key: user_product_detail_index
       key_len: 314
           ref: NULL
          rows: 9
      filtered: 100.00
         Extra: Using where; Using index
    *************************** 2. row ***************************
            id: 1
    select_type: SIMPLE
         table: user_info
    partitions: NULL
          type: eq_ref
    possible_keys: PRIMARY
           key: PRIMARY
       key_len: 8
           ref: test.order_info.user_id
          rows: 1
      filtered: 100.00
         Extra: NULL
    2 rows in set, 1 warning (0.00 sec)

    #ref: 此型別通常出現在多表的join 查詢, 針對於非唯一或非主鍵索引, 或是使用了
  • 最左前綴
  • 規則索引的查詢.

    例如下面這個例子中, 就使用到了ref 類型的查詢:

    mysql> EXPLAIN SELECT * FROM user_info, order_info WHERE user_info.id = order_info.user_id AND order_info.user_id = 5\G
    *************************** 1. row ***************************
            id: 1
    select_type: SIMPLE
         table: user_info
    partitions: NULL
          type: const
    possible_keys: PRIMARY
           key: PRIMARY
       key_len: 8
           ref: const
          rows: 1
      filtered: 100.00
         Extra: NULL
    *************************** 2. row ***************************
            id: 1
    select_type: SIMPLE
         table: order_info
    partitions: NULL
          type: ref
    possible_keys: user_product_detail_index
           key: user_product_detail_index
       key_len: 9
           ref: const
          rows: 1
      filtered: 100.00
         Extra: Using index
    2 rows in set, 1 warning (0.01 sec)

    range: 表示使用索引範圍查詢, 透過索引欄位範圍來取得表格中部分資料記錄. 這個型別通常出現在 =, , >, >=, , BETWEEN, IN() 操作中.
  • type


    range 時, 那麼EXPLAIN 輸出的ref 字段為NULL, 並且key_len 字段是此次查詢中使用到的索引的最長的那個.例如下面的例子就是一個範圍查詢:<pre class='brush:php;toolbar:false;'>mysql&gt; EXPLAIN SELECT * -&gt; FROM user_info -&gt; WHERE id BETWEEN 2 AND 8 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: user_info partitions: NULL type: range possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: NULL rows: 7 filtered: 100.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)</pre>

    #index: 表示全索引掃描(full index scan), 和ALL 類型類似, 只不過ALL 類型是全表掃描, 而index 類型則僅掃描所有的索引, 而不掃描資料.
  • index類型通常出現在: 所要查詢的資料直接在索引樹中就可以獲得到, 而不需要掃描資料. 當是這種情況時, Extra 欄位會顯示
  • Using index

    .

    #例如:
  • mysql> EXPLAIN SELECT name FROM  user_info \G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: user_info
       partitions: NULL
             type: index
    possible_keys: NULL
              key: name_index
          key_len: 152
              ref: NULL
             rows: 10
         filtered: 100.00
            Extra: Using index
    1 row in set, 1 warning (0.00 sec)
上面的例子中, 我們查詢的name 欄位恰好是一個索引, 因此我們直接從索引中取得資料就可以滿足查詢的需求了, 而不需要查詢表中的資料. 因此這樣的情況下, type 的值是

index

, 而Extra 的值是

Using index.#

  • ALL: 表示全表扫描, 这个类型的查询是性能最差的查询之一. 通常来说, 我们的查询不应该出现 ALL 类型的查询, 因为这样的查询在数据量大的情况下, 对数据库的性能是巨大的灾难. 如一个查询是 ALL 类型查询, 那么一般来说可以对相应的字段添加索引来避免.
    下面是一个全表扫描的例子, 可以看到, 在全表扫描时, possible_keys 和 key 字段都是 NULL, 表示没有使用到索引, 并且 rows 十分巨大, 因此整个查询效率是十分低下的.

    mysql> EXPLAIN SELECT age FROM  user_info WHERE age = 20 \G
    *************************** 1. row ***************************
            id: 1
    select_type: SIMPLE
         table: user_info
    partitions: NULL
          type: ALL
    possible_keys: NULL
           key: NULL
       key_len: NULL
           ref: NULL
          rows: 10
      filtered: 10.00
         Extra: Using where
    1 row in set, 1 warning (0.00 sec)

    type 类型的性能比较

    通常来说, 不同的 type 类型的性能关系如下:
    ALL <br><code>ALL 类型因为是全表扫描, 因此在相同的查询条件下, 它是速度最慢的.
    index 类型的查询虽然不是全表扫描, 但是它扫描了所有的索引, 因此比 ALL 类型的稍快.
    后面的几种类型都是利用了索引来查询数据, 因此可以过滤部分或大部分数据, 因此查询效率就比较高了.

possible_keys

possible_keys 表示 MySQL 在查询时, 能够使用到的索引. 注意, 即使有些索引在 possible_keys 中出现, 但是并不表示此索引会真正地被 MySQL 使用到. MySQL 在查询时具体使用了哪些索引, 由 key 字段决定.

key

此字段是 MySQL 在当前查询时所真正使用到的索引.

key_len

表示查询优化器使用了索引的字节数. 这个字段可以评估组合索引是否完全被使用, 或只有最左部分字段被使用到.
key_len 的计算规则如下:

  • 字符串

    • char(n): n 字节长度

    • varchar(n): 如果是 utf8 编码, 则是 3 n + 2字节; 如果是 utf8mb4 编码, 则是 4 n + 2 字节.

  • 数值类型:

    • TINYINT: 1字节

    • SMALLINT: 2字节

    • MEDIUMINT: 3字节

    • INT: 4字节

    • BIGINT: 8字节

  • 时间类型

    • DATE: 3字节

    • TIMESTAMP: 4字节

    • DATETIME: 8字节

  • 字段属性: NULL 属性 占用一个字节. 如果一个字段是 NOT NULL 的, 则没有此属性.

我们来举两个简单的栗子:

mysql> EXPLAIN SELECT * FROM order_info WHERE user_id < 3 AND product_name = &#39;p1&#39; AND productor = &#39;WHH&#39; \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: order_info
   partitions: NULL
         type: range
possible_keys: user_product_detail_index
          key: user_product_detail_index
      key_len: 9
          ref: NULL
         rows: 5
     filtered: 11.11
        Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)

上面的例子是从表 order_info 中查询指定的内容, 而我们从此表的建表语句中可以知道, 表 order_info 有一个联合索引:

KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`)

不过此查询语句 WHERE user_id 中, 因为先进行 user_id 的范围查询, 而根据 <code>最左前缀匹配 原则, 当遇到范围查询时, 就停止索引的匹配, 因此实际上我们使用到的索引的字段只有 user_id, 因此在 EXPLAIN    中, 显示的 key_len 为 9. 因为 user_id 字段是 BIGINT, 占用 8 字节, 而 NULL 属性占用一个字节, 因此总共是 9 个字节. 若我们将user_id 字段改为 BIGINT(20)  NOT NULL DEFAULT '0', 则 key_length 应该是8.

上面因为 最左前缀匹配 原则, 我们的查询仅仅使用到了联合索引的 user_id 字段, 因此效率不算高.

接下来我们来看一下下一个例子:

mysql> EXPLAIN SELECT * FROM order_info WHERE user_id = 1 AND product_name = &#39;p1&#39; \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: order_info
   partitions: NULL
         type: ref
possible_keys: user_product_detail_index
          key: user_product_detail_index
      key_len: 161
          ref: const,const
         rows: 2
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)

这次的查询中, 我们没有使用到范围查询, key_len 的值为 161. 为什么呢? 因为我们的查询条件 WHERE user_id = 1 AND product_name = 'p1' 中, 仅仅使用到了联合索引中的前两个字段, 因此 keyLen(user_id) + keyLen(product_name) = 9 + 50 * 3 + 2 = 161

rows

rows 也是一个重要的字段. MySQL 查询优化器根据统计信息, 估算 SQL 要查找到结果集需要扫描读取的数据行数.
这个值非常直观显示 SQL 的效率好坏, 原则上 rows 越少越好.

Extra

EXplain 中的很多额外的信息会在 Extra 字段显示, 常见的有以下几种内容:

  • Using filesort
    当 Extra 中有 Using filesort 时, 表示 MySQL 需额外的排序操作, 不能通过索引顺序达到排序效果. 一般有 Using filesort, 都建议优化去掉, 因为这样的查询 CPU 资源消耗大.
    例如下面的例子:

    mysql> EXPLAIN SELECT * FROM order_info ORDER BY product_name \G
    *************************** 1. row ***************************
            id: 1
    select_type: SIMPLE
         table: order_info
    partitions: NULL
          type: index
    possible_keys: NULL
           key: user_product_detail_index
       key_len: 253
           ref: NULL
          rows: 9
      filtered: 100.00
         Extra: Using index; Using filesort
    1 row in set, 1 warning (0.00 sec)

我们的索引是

KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`)

但是上面的查询中根据 product_name 来排序, 因此不能使用索引进行优化, 进而会产生 Using filesort.
如果我们将排序依据改为 ORDER BY user_id, product_name, 那么就不会出现 Using filesort 了. 例如:

mysql> EXPLAIN SELECT * FROM order_info ORDER BY user_id, product_name \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: order_info
   partitions: NULL
         type: index
possible_keys: NULL
          key: user_product_detail_index
      key_len: 253
          ref: NULL
         rows: 9
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)
  • Using index
    "覆盖索引扫描", 表示查询在索引树中就可查找所需数据, 不用扫描表数据文件, 往往说明性能不错

  • Using temporary
    查询有使用临时表, 一般出现于排序, 分组和多表 join 的情况, 查询效率不高, 建议优化.

【相关推荐】

1. 免费mysql在线视频教程

2. MySQL最新手册教程

3. 布尔教育燕十八mysql入门视频教程

以上是MySQL 效能最佳化--Explain 使用介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
MySQL:初學者的基本技能MySQL:初學者的基本技能Apr 18, 2025 am 12:24 AM

MySQL適合初學者學習數據庫技能。 1.安裝MySQL服務器和客戶端工具。 2.理解基本SQL查詢,如SELECT。 3.掌握數據操作:創建表、插入、更新、刪除數據。 4.學習高級技巧:子查詢和窗口函數。 5.調試和優化:檢查語法、使用索引、避免SELECT*,並使用LIMIT。

MySQL:結構化數據和關係數據庫MySQL:結構化數據和關係數據庫Apr 18, 2025 am 12:22 AM

MySQL通過表結構和SQL查詢高效管理結構化數據,並通過外鍵實現表間關係。 1.創建表時定義數據格式和類型。 2.使用外鍵建立表間關係。 3.通過索引和查詢優化提高性能。 4.定期備份和監控數據庫確保數據安全和性能優化。

MySQL:解釋的關鍵功能和功能MySQL:解釋的關鍵功能和功能Apr 18, 2025 am 12:17 AM

MySQL是一個開源的關係型數據庫管理系統,廣泛應用於Web開發。它的關鍵特性包括:1.支持多種存儲引擎,如InnoDB和MyISAM,適用於不同場景;2.提供主從復制功能,利於負載均衡和數據備份;3.通過查詢優化和索引使用提高查詢效率。

SQL的目的:與MySQL數據庫進行交互SQL的目的:與MySQL數據庫進行交互Apr 18, 2025 am 12:12 AM

SQL用於與MySQL數據庫交互,實現數據的增、刪、改、查及數據庫設計。 1)SQL通過SELECT、INSERT、UPDATE、DELETE語句進行數據操作;2)使用CREATE、ALTER、DROP語句進行數據庫設計和管理;3)複雜查詢和數據分析通過SQL實現,提升業務決策效率。

初學者的MySQL:開始數據庫管理初學者的MySQL:開始數據庫管理Apr 18, 2025 am 12:10 AM

MySQL的基本操作包括創建數據庫、表格,及使用SQL進行數據的CRUD操作。 1.創建數據庫:CREATEDATABASEmy_first_db;2.創建表格:CREATETABLEbooks(idINTAUTO_INCREMENTPRIMARYKEY,titleVARCHAR(100)NOTNULL,authorVARCHAR(100)NOTNULL,published_yearINT);3.插入數據:INSERTINTObooks(title,author,published_year)VA

MySQL的角色:Web應用程序中的數據庫MySQL的角色:Web應用程序中的數據庫Apr 17, 2025 am 12:23 AM

MySQL在Web應用中的主要作用是存儲和管理數據。 1.MySQL高效處理用戶信息、產品目錄和交易記錄等數據。 2.通過SQL查詢,開發者能從數據庫提取信息生成動態內容。 3.MySQL基於客戶端-服務器模型工作,確保查詢速度可接受。

mysql:構建您的第一個數據庫mysql:構建您的第一個數據庫Apr 17, 2025 am 12:22 AM

構建MySQL數據庫的步驟包括:1.創建數據庫和表,2.插入數據,3.進行查詢。首先,使用CREATEDATABASE和CREATETABLE語句創建數據庫和表,然後用INSERTINTO語句插入數據,最後用SELECT語句查詢數據。

MySQL:一種對數據存儲的初學者友好方法MySQL:一種對數據存儲的初學者友好方法Apr 17, 2025 am 12:21 AM

MySQL適合初學者,因為它易用且功能強大。 1.MySQL是關係型數據庫,使用SQL進行CRUD操作。 2.安裝簡單,需配置root用戶密碼。 3.使用INSERT、UPDATE、DELETE、SELECT進行數據操作。 4.複雜查詢可使用ORDERBY、WHERE和JOIN。 5.調試需檢查語法,使用EXPLAIN分析查詢。 6.優化建議包括使用索引、選擇合適數據類型和良好編程習慣。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具