搞定面試官 - MySQL 中你知道如何計算一個索引的長度嘛?

大家好,我是程序員啊粥。

今天給大家分享一個我遇到過的比較少見的面試題,那就是 MySQL 中如何計算一個索引的長度。

說實話,我第一次遇到這個問題的時候想當然的以爲索引長度就是我們建表時定義的字段長度,如果是聯合索引,那就是多個字段長度相加。

事實證明,在我說出上述回答之後,面試官就讓我帶着簡歷跑路了。

於是乎,我仔細查閱了相關資料,發現索引長度這個計算方式還是有點意思的,索性給大家分享一下。

首先,我們要知道 MySQL Innodb 引擎對於索引的長度是有限制的,最大爲 767 字節。

你採用不同的字符編碼方式,對應的字節數是不一樣的,比如我們最常用的 utf8mb4 字符集是 4 字節字符集,則 767 字節 / 4 字節每字符 = 191字符(默認索引最大長度),所以在 varchar(255) 或 char(255) 類型字段上創建索引會失敗,報錯會提示最大索引長度爲 767 字節。

其他的一些編碼方式對應關係分別是:latin1 編碼的,一個字符佔用一個字節,gbk 編碼的,一個字符佔用兩個字節,utf8 編碼的,一個字符佔用三個字節。

總的來說,索引長度計算規則爲:

  1. 所有的索引字段,如果沒有設置 Not Null,則需要加一個字節(這也是我們爲什麼建議建表時不要有 Null 字段的原因之一)。

  2. 對於定長字段,int 類型佔四個字節、date 佔三個字節、char(n) 佔 N 個字符。

  3. 對於變成字段 varchar(n),則是 N 個字符 + 兩個字節。

  4. 不同的字符集,一個字符佔用的字節數不同。latin1編碼的,一個字符佔用一個字節,gbk編碼的,一個字符佔用兩個字節,utf8編碼的,一個字符佔用三個字節。

  5. 索引長度 char()、varchar() 索引長度的計算公式:

Character Set:utf8mb4=4,utf8=3,gbk=2,latin1=1) * 列長度 + 1(允許 Null) + 2(變長列)

基於以上原則,我們建張表來驗證下:

CREATE TABLE `tb_item` (
  `id` bigint NOT NULL COMMENT '書籍id,同時也是書籍編號',
  `title` varchar(100) NOT NULL COMMENT '書籍名稱',
  `sell_point` varchar(500) DEFAULT NULL COMMENT '書籍賣點',
  `price` bigint NOT NULL COMMENT '書籍價格,單位爲:分',
  `num` int NOT NULL COMMENT '庫存數量',
  `barcode` varchar(30) DEFAULT NULL COMMENT '書籍條形碼',
  `image` varchar(500) DEFAULT NULL COMMENT '書籍圖片',
  `cid` bigint NOT NULL COMMENT '所屬類目,葉子類目',
  `status` tinyint NOT NULL DEFAULT '1' COMMENT '書籍狀態,1-正常,2-下架,3-刪除',
  `created` datetime NOT NULL COMMENT '創建時間',
  `updated` datetime NOT NULL COMMENT '更新時間',
  `upload_id` bigint DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `cid` (`cid`),
  KEY `status` (`status`),
  KEY `updated` (`updated`),
  KEY `tb_item_title_price_num` (`title`,`price`,`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='書籍表';

在這張表上我們建立了聯合索引 tb_item_title_price_num ,由三個字段組成,分別是變長字段 varchar,定長字段 price 以及 num。

我們先來執行如下這條語句:

explain select * from tb_item where title = '編譯原理' and price = 45 and num = 23232;

我們看到 key 是 tb_item_title_price_num,同時索引長度 key_len 爲 314 ,證明是使用到了聯合索引 tb_item_title_price_num 的三個完整字段的。

file

這個 314 的具體計算方式爲:

字符集我們建表時用的爲 utf8 編碼,所以 title 字段的索引長度是 3 * 100 + 0 + 2 = 302,price 字段的索引長度是 8,num 字段的索引長度是 4。

因此 tb_item_title_price_num 索引總共長度是 302 + 8 + 4 = 314。

爲了驗證我們的計算方式,接下來我們再執行如下語句,使得索引部分失效。

explain select * from tb_item where title = '編譯原理' and num = 23232

這條語句因爲我們跳過了 price 字段,所以聯合索引中只會有 title 字段生效,剩餘部分都會失效,如果我們計算方式沒有問題的話,那麼此時執行計劃中的 key_len 應該爲 302。

file

果然,我們看到 key_len 已經變成了 302,這意味着索引部分失效了,只有 title 字段索引起了作用,同時 Extra 爲 Using index condition,說明使用了索引,但是需要回表查詢數據。

具體 explain 執行計劃中其他字段的具體含義,參考這篇文章。

好了,我們今天的內容就到這裏了。

簡單總結一下,在 MySQL 中,索引長度不僅取決於我們建表時設置的字段長度,還和具體的字符集編碼以及字段是否允許爲 Null 等多個條件相關,字段長度只能作爲索引長度的預估項,而不是準確值。

我是程序員啊粥,關注我,我們一起在技術海洋中向上生長。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章