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 相同再依次比較 Cid 和 SId,最後得到檢索的資料;
但當(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個欄位。