1. 程式人生 > 其它 >MYSQL聯合索引原理之最左匹配原則

MYSQL聯合索引原理之最左匹配原則

在mysql建立聯合索引時會遵循最左字首匹配的原則,即最左優先,在檢索資料時從聯合索引的最左邊開始匹配。

示例:

CREATE TABLE `student` (
  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
  `Gid` int(11) unsigned DEFAULT NULL COMMENT '年級id',
  `Cid` int(11) unsigned DEFAULT NULL COMMENT '班級id',
  `SId` int(11) unsigned DEFAULT NULL COMMENT '學號',
  `Name` varchar(
10) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '姓名', PRIMARY KEY (`Id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

對列Gid、列Cid和列Sid建一個聯合索引:

create unique index uni_Gid_Cid_SId on student(Gid,Cid,SId);

聯合索引uni_Gid_Cid_SId實際建立了(Gid)、(Gid,Cid)、(Gid,SId)、(Gid,Cid,SId)四個索引。

插入模擬資料:

INSERT INTO `student` (`Gid`, `Cid`, `SId`, `Name`) VALUES (floor(rand() * rand() *rand() * 1000000000) , floor(rand() *  rand() *rand() * 1000000000) , floor(rand() * rand() * rand() *1000000000) , rand());

查詢示例:

SELECT * FROM student WHERE Gid=16236196 AND Cid=8143382 AND Name='0.76727119';
EXPLAIN SELECT
* FROM student WHERE Gid=16236196 AND Cid=8143382 AND Name='0.76727119';

上面這個查詢語句執行時會依照最左字首匹配原則,檢索時會使用索引(Gid,Cid)進行資料匹配。

索引的欄位可以是任意順序的,如:

SELECT * FROM student WHERE Gid=16236196 AND Cid=8143382;
SELECT * FROM student WHERE Cid=8143382 AND Gid=16236196 ;

聯合索引uni_Gid_Cid_SId 還支援的查詢條件有:

select * from table where Gid = 1;

select * from table where Gid = 1 and  Cid =1;

select * from table where Gid = 1 and  Cid=1 and SId= 1;

select * from table where Gid= 1 and SId= 1;

關於最後一個的結構 Gid和SId也會走索引uni_Gid_Cid_SId的原理是:

  b+樹的資料項是複合的資料結構,比如(Gid,Cid,SId)的時候,b+數是按照從左到右的順序來建立搜尋樹的。

  比如當(111,222,333)這樣的資料來檢索的時候,b+樹會優先比較 Gid 來確定下一步的所搜方向,如果 Gid 相同再依次比較 CidSId,最後得到檢索的資料;

  但當(222,333)這樣的沒有 Gid的資料來的時候,b+樹就不知道下一步該查哪個節點,因為建立搜尋樹的時候 Gid 就是第一個比較因子,必須要先根據 Gid 來搜尋才能知道下一步去哪裡查詢。

  比如當(111,333)這樣的資料來檢索時,b+樹可以用 Gid 來指定搜尋方向,但下一個欄位 Cid 的缺失,所以只能把 Gid 等於 111 的資料都找到,然後再匹配 SId是 333 的資料了, 這個是非常重要的性質,即索引的最左匹配特性。

為什麼要使用聯合索引:

減少開銷

  建一個聯合索引(Gid,Cid,SId),實際相當於建了(Gid)、(Gid,Cid)、(Gid,SId)、(Gid,Cid,SId)四個索引。每多一個索引,都會增加寫操作的開銷和磁碟空間的開銷。對於大量資料的表,使用聯合索引會大大的減少開銷!

覆蓋索引。

  對聯合索引(Gid,Cid,SId),如果有如下的SQL::SELECE Gid,Cid,SId FROM student WHERE Gid=1AND Cid=2。那麼MySQL可以直接通過遍歷索引取得資料,而無需回表,這減少了很多的隨機io操作。減少io操作,特別的隨機io其實是dba主要的優化策略。所以,在真正的實際應用中,覆蓋索引是主要的提升效能的優化手段之一。

效率高。

  索引列越多,通過索引篩選出的資料越少。

  有1000W條資料的表,有如下SQL:SELECT * FROM TABLE WHERE Gid=1 AND Cid=2AND SId=3,假設假設每個條件可以篩選出10%的資料,如果只有單值索引,那麼通過該索引能篩選出1000W10%=100w條資料,然後再回表從100w條資料中找到符合Gid=2 and Cid= 3的資料,然後再排序,再分頁;如果是聯合索引,通過索引篩選出1000w10% 10% *10%=1w,效率提升可想而知!

缺點。

  聯合索引越多,索引列越多,則建立的索引越多,索引都是儲存在磁盤裡的,通過索引演算法 (Btree代表索引演算法使用二叉樹的形式來做索引的) 來查詢資料,的確可以極大的提高查詢效率,但是與此同時增刪改的同時,需要更新索引,同樣是需要花時間的,並且索引所佔的磁碟空間也不小。

建議。

  單表儘可能不要超過一個聯合索引,單個聯合索引不超過3個欄位。