首頁 > 軟體

總結三道MySQL聯合索引面試題

2022-08-16 14:06:49

前言:

眾所周知MySQL聯合索引遵循最左字首匹配原則,在少數情況下也會不遵循(有興趣,可以翻一下上篇文章

建立聯合索引的時候,建議優先把區分度高的欄位放在第一列。

至於怎麼統計區分度,可以按照下面這種方式。

建立一張測試表,用來測試:

CREATE TABLE `test` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `a` int NOT NULL,
  `b` int NOT NULL,
  `c` int NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='測試表';

統計每個欄位的區分度:

select 
    count(distinct a)/count(*), 
    count(distinct b)/count(*),
    count(distinct c)/count(*)
from test;

值越大,區分度越高,優先放在第一列。

很多人不知道聯合索引在B+樹中是怎麼儲存的?我簡單畫一下。

比如在(a,b)欄位上面建立聯合索引,儲存結構類似下面這樣:

葉子節點儲存全部資料,用雙連結串列指標相連,資料都是先按a欄位排序,a欄位的值相等時再按b欄位排序。

a欄位的值是全域性有序的,分別有1,1,1,2,2,2。

b欄位的值是全域性無序的,分別有1,3,5,1,3,5,只有在a欄位的值相等時才呈現出區域性有序。

所以在進行SQL查詢的時候,如果where條件中沒有a欄位,只有b欄位,是無法用到索引的,像下面這樣:

select * from test where b=1;

像有些文章上面說的,在(a,b)兩個欄位上建立聯合索引,就會建立兩個索引,分別是(a)和(a,b),這其實是一種不恰當的表述,雖然結果是對的。

下面做幾道聯合索引的經典面試題,試一下大家掌握的怎麼樣?

第一題:

下面這條SQL,該怎麼建立聯合索引?

SELECT * FROM test WHERE a = 1 and b = 1 and c = 1;

你以為的答案是(a,b,c),其實答案是6個,abc三個的排列組合,(a,b,c)、(a,c,b)、(b,a,c)、(b,c,a)、(c,a,b)、(c,b,a)。

MySQL優化器為了適應索引,會調整條件的順序。

再給面試官補充一句,區分度高的欄位放在最前面,大大加分。

第二題:

下面這條SQL,該怎麼建立聯合索引

SELECT * FROM test WHERE a = 1 and b > 1 and c = 1;

考察的知識點是: 聯合索引遇到範圍匹配會停止,不會再匹配後面的索引欄位。

所以答案應該是:(a,c,b)和 (c,a,b)。

當建立(a,c,b)和 (c,a,b)索引的時候,查詢會用到3個欄位的索引,效率更高。

怎麼判斷是用到了3個欄位的索引,而不是隻用到前兩個欄位的索引呢?

有個非常簡單的方法,看執行計劃的索引長度。

由於int型別的欄位佔4個位元組,3個欄位長度剛好是12個位元組。

第三題:

下面這條SQL,該怎麼建立聯合索引

SELECT * FROM test WHERE a in (1,2,3) and b > 1;

答案是(a,b)。in條件查詢會被轉換成等值查詢,可以驗證一下:

可以看到用到了兩個欄位的索引。

所以我們在平時做開發,儘量想辦法把範圍查詢轉換成in條件查詢,效率更高。

到此這篇關於總結三道MySQL聯合索引面試題的文章就介紹到這了,更多相關MySQL聯合索引內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com