背景:
為了提高資料庫效率,建索引是家常便飯;那麼當查詢條件為2個及以上時,我們是建立多個單列索引還是建立乙個聯合索引好呢?他們之間的區別是什麼?哪個效率高呢?我在這裡詳細測試分析下。
一、聯合索引測試
注:mysql版本為 5.7.20
建立測試表(表記錄數為63188):
create table `t_mobilesms_11` (
`id` bigint(20) not null auto_increment,
`userid` varchar(255) character set utf8 collate utf8_bin not null default '' comment '使用者id,建立任務時的userid',
`mobile` varchar(24) not null default '' comment '手機號碼',
`billmonth` varchar(32) default null comment '賬單月',
`time` varchar(32) default null comment '收/發簡訊時間',
`peernumber` varchar(64) not null comment '對方號碼',
`location` varchar(64) default null comment '通訊地(自己的)',
`sendtype` varchar(16) default null comment 'send-傳送; receive-收取',
`msgtype` varchar(8) default null comment 'sms-簡訊; mss-彩信',
`servicename` varchar(256) default null comment '業務名稱. e.g. 點對點(網內)',
`fee` int(11) default null comment '通訊費(單位分)',
`createtime` datetime default null comment '建立時間',
`lastmodifytime` datetime default null comment '最後修改時間',
primary key (`id`),
key `聯合索引` (`userid`,`mobile`,`billmonth`)
) engine=innodb auto_increment=71185 default charset=utf8 comment='手機簡訊詳情'12
3456
78910
1112
1314
1516
17我們為userid, mobile, billmonth三個字段新增上聯合索引!
我們選擇 explain 檢視執行計畫來觀察索引利用情況:
1.查詢條件為 userid
explain select * from `t_mobilesms_11` where userid='2222'
1可以通過key看到,聯合索引有效
2.查詢條件為 mobile
explain select * from `t_mobilesms_11` where mobile='13281899972'
1可以看到聯合索引無效
3.查詢條件為 billmonth
explain select * from `t_mobilesms_11` where billmonth='2018-04'
1聯合索引無效
4.查詢條件為 userid and mobile
explain select * from `t_mobilesms_11` where userid='2222' and mobile='13281899972'
1聯合索引有效
5.查詢條件為 mobile and userid
explain select * from `t_mobilesms_11` where mobile='13281899972' and userid='2222'
1在4的基礎上調換了查詢條件的順序,發現聯合索引依舊有效
6.查詢條件為 userid or mobile
explain select * from `t_mobilesms_11` where userid='2222' or mobile='13281899972'
1把 and 換成 or,發現聯合所索引無效!
7.查詢條件為 userid and billmonth
explain select * from `t_mobilesms_11` where userid='2222' and billmonth='2018-04'
1這兩個條件分別位於聯合索引位置的第一和第三,測試聯合索引依舊有效!
8.查詢條件為 mobile and billmonth
explain select * from `t_mobilesms_11` where mobile='13281899972' and billmonth='2018-04'
1這兩個條件分別位於聯合索引位置的第二和第三,發現聯合索引無效!
9.查詢條件為 userid and mobile and billmonth
explain select * from `t_mobilesms_11` where userid='2222' and mobile='13281899972' and billmonth='2018-04'
1所有條件一起查詢,聯合索引有效!(當然,這才是最正統的用法啊!)
二、單列索引測試
建立三個單列索引:
1.查詢條件為 userid and mobile and billmonth
explain select * from `t_mobilesms_11` where userid='2222' and mobile='13281899972' and billmonth='2018-04'
1我們發現三個單列索引只有 userid 有效(位置為查詢條件第乙個),其他兩個都沒有用上。
那麼為什麼沒有用上呢?按照我們的理解,三個欄位都加索引了,無論怎麼排列組合查詢,應該都能利用到這三個索引才對!
其實這裡其實涉及到了mysql優化器的優化策略!當多條件聯合查詢時,優化器會評估用哪個條件的索引效率最高!它會選擇最佳的索引去使用,也就是說,此處userid 、mobile 、billmonth這三個索引列都能用,只不過優化器判斷只需要使用userid這乙個索引就能完成本次查詢,故最終explain展示的key為userid。
當然,如果優化器判斷本次查詢非要全使用三個索引才能效率最高,那麼explain的key就會是userid 、mobile 、billmonth,都會生效!
2.查詢條件為 mobile and billmonth
explain select * from `t_mobilesms_11` where mobile='13281899972' and billmonth='2018-04'
1我們發現此處兩個查詢條件只有 mobile 生效(位置也為查詢條件第乙個)
3.查詢條件為 userid or mobile
explain select * from `t_mobilesms_11` where userid='2222' or mobile='13281899972'
1這次把 and 換成 or,發現兩個查詢條件都用上索引了!
三、結論
通俗理解:
利用索引中的附加列,您可以縮小搜尋的範圍,但使用乙個具有兩列的索引 不同於使用兩個單獨的索引。復合索引的結構與**簿類似,人名由姓和名構成,**簿首先按姓氏對進行排序,然後按名字對有相同姓氏的人進行排序。如果您知道姓,**簿將非常有用;如果您知道姓和名,**簿則更為有用,但如果您只知道名不姓,**簿將沒有用處。
所以說建立復合索引時,應該仔細考慮列的順序。對索引中的所有列執行搜尋或僅對前幾列執行搜尋時,復合索引非常有用;僅對後面的任意列執行搜尋時,復合索引則沒有用處。
重點:多個單列索引在多條件查詢時優化器會選擇最優索引策略,可能只用乙個索引,也可能將多個索引全用上! 但多個單列索引底層會建立多個b+索引樹,比較占用空間,也會浪費一定搜尋效率,故如果只有多條件聯合查詢時最好建聯合索引!
最左字首原則:
顧名思義是最左優先,以最左邊的為起點任何連續的索引都能匹配上,
注:如果第乙個欄位是範圍查詢需要單獨建乙個索引
注:在建立聯合索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。這樣的話擴充套件性較好,比如 userid 經常需要作為查詢條件,而 mobile 不常常用,則需要把 userid 放在聯合索引的第一位置,即最左邊
同時存在聯合索引和單列索引(欄位有重複的),這個時候查詢mysql會怎麼用索引呢?
這個涉及到mysql本身的查詢優化器策略了,當乙個表有多條索引可走時, mysql 根據查詢語句的成本來選擇走哪條索引;
聯合索引本質:
當建立**(a,b,c)聯合索引時,相當於建立了(a)單列索引**,(a,b)聯合索引以及**(a,b,c)聯合索引**
想要索引生效的話,只能使用 a和a,b和a,b,c三種組合;當然,我們上面測試過,a,c組合也可以,但實際上只用到了a的索引,c並沒有用到!
注:這個可以結合上邊的 通俗理解 來思考!
其他知識點:
1、需要加索引的字段,要在where條件中
2、資料量少的字段不需要加索引;因為建索引有一定開銷,如果資料量小則沒必要建索引(速度反而慢)
3、如果where條件中是or關係,加索引在某些場景下不起作用(詳細參考
4、聯合索引比對每個列分別建索引更有優勢,因為索引建立得越多就越佔磁碟空間,在更新資料的時候速度會更慢。另外建立多列索引時,順序也是需要注意的,應該將嚴格的索引放在前面,這樣篩選的力度會更大,效率更高。
復合索引和多個單列索引的區別
多個單列索引 在每個需要索引的字段上設定乙個索引 復合索引 根據查詢需求在多個字段設定乙個索引 區別 1 多個單列索引實現簡單,那個字段需要就在 加,而復合索引的話,需要根據需求,考慮好索引順序設定索引。2 再查詢中,如果查詢條件使用where連線的,則多個單列索引中只有乙個索引會生效,而復合索引在...
MySQL單列索引和聯合索引
所有的mysql列型別能被索引。在相關的列上的使用索引是改進select操作效能的最好方法。乙個表最多可有16個索引。最大索引長度是256個位元組,儘管這可以在編譯mysql時被改變。對於char和varchar列,你可以索引列的字首。這更快並且比索引整個列需要較少的磁碟空間。在create tab...
MySQL單列索引和聯合索引
mysql單列索引和聯合索引 所有的mysql列型別能被索引。在相關的列上的使用索引是改進select操作效能的最好方法。乙個表最多可有16個索引。最大索引長度是256個位元組,儘管這可以在編譯mysql時被改變。對於char和varchar列,你可以索引列的字首。這更快並且比索引整個列需要較少的磁...