iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
Software Development

MYSQL-相關實務操作學習紀錄系列 第 23

Day.23 分析語法效能必備 - MYSQL語法優化 ( Explain)

  • 分享至 

  • xImage
  •  

在前面的日誌介紹中,可以透過slow log紀錄去找到有問題執行時間久的SQL語句,那有了資料後該如何去改善優化?

在查詢SQL前加上(EXPLAIN指令)返回的資訊能幫助你分析這句SQL執行的方式,判斷資料表中建立的索引有沒有如預期的去使用到該組合,提升查詢效率。

以熟悉的例子來用,先看以下表結構XD /images/emoticon/emoticon07.gif


CREATE TABLE `act` (
  `actives_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `status` tinyint(4) NOT NULL,
  `start_time` int(11) unsigned NOT NULL,
  `end_time` int(11) unsigned NOT NULL,
  `platform_id` bigint(20) NOT NULL,
  `updated_at` int(11) unsigned NOT NULL,
  `created_at` int(11) unsigned NOT NULL,
  PRIMARY KEY (`actives_id`),
  KEY `pid_status` (`platform_id`,`status`)
)

 CREATE TABLE `act_name` (
  `actives_id` bigint(20) NOT NULL COMMENT 'ID',
  `actives_name` varchar(40) NOT NULL,
  `language` varchar(40) NOT NULL,
  `created_at` int(11) unsigned NOT NULL,
  PRIMARY KEY (`actives_id`,`language`)
)

CREATE TABLE `act_game` (
  `actives_id` bigint(20) NOT NULL COMMENT 'ID',
  `game_name` varchar(40) NOT NULL,
  `support_rules` text NOT NULL,
  `type` tinyint(4) NOT NULL,
  `created_at` int(11) unsigned NOT NULL,
  PRIMARY KEY (`actives_id`,`game_name`),
  KEY `game` (`game_name`)
)

mysql>  select * from act;
+------------+--------+------------+------------+----------------+------------+------------+
| actives_id | status | start_time | end_time   | platform_id    | updated_at | created_at |
+------------+--------+------------+------------+----------------+------------+------------+
|          1 |      1 | 1611504000 | 1632931200 | 10868213102191 | 1632499200 | 1632499200 |
+------------+--------+------------+------------+----------------+------------+------------+
1 row in set (0.00 sec)

mysql> select * from act_game;
+------------+-----------------+-------------------------------+------+------------+
| actives_id | game_name       | support_rules                 | type | created_at |
+------------+-----------------+-------------------------------+------+------------+
|          1 | INVEST-ITHOME21 | ["w102","w103","q200","z920"] |    7 | 1632499200 |
|          2 | INVEST-ITHOME99 | ["z920"]                      |    5 | 1632499200 |
+------------+-----------------+-------------------------------+------+------------+
2 rows in set (0.00 sec)

mysql> select * from act_name;
+------------+--------------+----------+------------+
| actives_id | actives_name | language | created_at |
+------------+--------------+----------+------------+
|          1 | test2        | ch       | 1632499205 |
|          1 | test1        | en       | 1632499200 |
|          1 | test3        | jp       | 1632499209 |
|          3 | test01       | ch       | 1632499220 |
|          3 | test02       | en       | 1632499225 |
|          3 | test03       | jp       | 1632499230 |
+------------+--------------+----------+------------+
6 rows in set (0.00 sec)

(分析) Example: 搜尋活動ID=1資料SQL

explain select * from act where actives_id = 1;

在該表結構中actives_id為我們的PK,在此搜尋條件下的分析中確實使用到的index就是PRIMARY。

看到分析中的Key欄位部分,顯示了mysql實際採用哪個索引來優化對該表的訪問,如果SQL沒有使用到任何索引值會是NULL。
https://ithelp.ithome.com.tw/upload/images/20210926/20130880eWAlRDyrNK.png


認識EXPLAIN分析中各欄位值意義

  • id
    查詢標示符。

    注意:
    一句查詢中可能根據條件子查詢等可能會有多筆執行分析。

    ID大小: id值越大,優先度高也代表越先執行。
    ID相同: 代表相同的優先度,執行順序可以由上往下看就好。

Example:
https://ithelp.ithome.com.tw/upload/images/20210929/20130880N08MdjFtxT.png

  • select_type
    顯示查詢的類型。 ps.看上面圖馬上能了解~

Example:
https://ithelp.ithome.com.tw/upload/images/20210928/20130880eQn5GcFhy5.png

  • table
    顯示查詢使用的表名。

  • partitions
    顯示此查詢命中了有做資料表分區的哪些分區。

    • 明天會介紹分區(partition)內容/images/emoticon/emoticon34.gif
  • type -重要-
    顯示連接使用的類型,可以用來判斷該語句執行效能好壞。這邊對幾個常見的做範例~

    • 類型分類排序(最優 -> 差)

      • System : const type的特殊情況。

      • const : 查詢使用主鍵或唯一索引時,表返回僅有一行。
        https://ithelp.ithome.com.tw/upload/images/20210928/20130880mFjuZrBRu4.png

      • eq_ref : 在連結表查詢中使用PK唯一索引作為關聯條件時,返回的資料對於前表的每個結果都只能匹配到後表的一行結果。
        透過下面舉例看這段話的意思比較一下差異~
        https://ithelp.ithome.com.tw/upload/images/20210929/20130880EmoXyYKy9f.png

      • ref : 一般針對於使用非唯一索引的查詢,或普通索引查詢的條件滿足索引的最左匹配原則(不知道的回去看幾篇文章有提到複合索引的最左匹配原則)。

        Example. 在act表中有一組索引: pid_status(platform_id,status)

      https://ithelp.ithome.com.tw/upload/images/20210928/20130880poyjpyqFBs.png

      • fulltext : 使用到全文索引。 MYSQL 全文索引

      • ref_or_null : 類似於ref,差別在於條件中對NULL資料的額外查詢。

        因為我們的表結構關係,這樣設定會吃不到所以做一下調整。

        1.PK 改成actives_id讓 is null 判斷條件觸發。
        2.新增一組普通索引 game (game_name)。

         CREATE TABLE `act_test` (
          `actives_id` bigint(20) NOT NULL COMMENT 'ID',
          `game_name` varchar(40) DEFAULT NULL,
          `support_rules` text NOT NULL,
          `type` tinyint(4) NOT NULL,
          `created_at` int(11) unsigned NOT NULL,
          PRIMARY KEY (`actives_id`) USING BTREE,
          KEY `game` (`game_name`)
        )
        

      https://ithelp.ithome.com.tw/upload/images/20210929/20130880YMdTUToptq.png

      • index_merge : 一個查詢中使用到索引合併優化觸發。

      • range : 使用到索引的範圍查詢。ex.(between , <= ...)
        https://ithelp.ithome.com.tw/upload/images/20210928/20130880S7vEo76cC6.png

      • index : 全索引掃描。和ALL差別在於index是針對index tree掃描,ALL則是全表數據都掃。
        https://ithelp.ithome.com.tw/upload/images/20210928/20130880u9oya8tFsC.png

      • ALL : 全表掃描。
        https://ithelp.ithome.com.tw/upload/images/20210928/20130880xmwuGoVttx.png
        當資料量大時在實務上的查詢,分析出來是這個代表該優化囉XD/images/emoticon/emoticon16.gif

  • possible_keys
    可能使用到的索引。

  • key -重要-
    實際查詢使用到的索引。

  • key_len
    顯示查詢使用的索引長度。
    (基本上越短越好,至於不同型態的長度計算規則有興趣可以去看看~)

  • ref
    顯示哪些列or常量與指定索引的比較。
    ex.常見的const: 使用常量等值查询,null...

  • rows -重要-
    執行本次查詢找到結果估計需要讀取的數據行數。
    (就是說你這句查詢需要掃描的行數,所以理想狀態是越少越好。)

  • filtered
    顯示查詢返回後的數據在過濾後剩下滿足條件的紀錄數比例。

  • Extra -重要-
    顯示如何解析此查詢的附加訊息。
    (這裡的輔助資訊很重要!能幫助你針對語法的缺點做對應優化)

Example常見的

  • Using where: 有通過where的條件去過濾需要的內容。

  • Using temporary: 有使用到臨時表。

  • Using index: 使用到覆蓋索引。(不知道的回前2天文章看有提到~)

  • Using filesort: 查詢的內容需做额外的排序,無法透過索引的順序達到排序。 (欠優化)

    ....


到這裡對優化的訊息有了基本的認識,不過說真的實際去做語法優化又是另一回事,能給你方向但不代表index照著敘述規則設定一定會得到對應資訊吃到index,可能會因為其他因素導致,重點還是在於經驗的累積。 /images/emoticon/emoticon28.gif

參考文件:
MYSQL EXPLAIN官方文件
https://database.51cto.com/art/202005/617071.htm


上一篇
Day.22 SQL應用 - 表與表之間的連結 (JOIN)
下一篇
Day.24 提升大數據資料管理 - 資料表分區 ( MYSQL Partition)
系列文
MYSQL-相關實務操作學習紀錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言