在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=1 AND Cid=2。那么MySQL可以直接通過遍歷索引取得數據,而無需回表,這減少了很多的隨機io操作。減少io操作,特別的隨機io其實是dba主要的優化策略。所以,在真正的實際應用中,覆蓋索引是主要的提升性能的優化手段之一。
效率高。
索引列越多,通過索引篩選出的數據越少。
有1000W條數據的表,有如下SQL:SELECT * FROM TABLE WHERE Gid=1 AND Cid=2 AND SId=3,假設假設每個條件可以篩選出10%的數據,如果只有單值索引,那么通過該索引能篩選出1000W10%=100w條數據,然后再回表從100w條數據中找到符合Gid=2 and Cid= 3的數據,然后再排序,再分頁;如果是聯合索引,通過索引篩選出1000w10% 10% *10%=1w,效率提升可想而知!
缺點。
聯合索引越多,索引列越多,則創建的索引越多,索引都是存儲在磁盤里的,通過索引算法 (Btree代表索引算法使用二叉樹的形式來做索引的) 來查找數據,的確可以極大的提高查詢效率,但是與此同時增刪改的同時,需要更新索引,同樣是需要花時間的,並且索引所占的磁盤空間也不小。
建議。
單表盡可能不要超過一個聯合索引,單個聯合索引不超過3個字段。