繼上一篇分析的索引問題后锁摔,我們知道了索引的作用和結(jié)構(gòu)恢暖,這一篇文章將繼續(xù)圍繞索引的一些類型知識(shí)點(diǎn)進(jìn)行分析
索引分為聚簇索引和非聚簇索引浩峡,那么這兩者之間是有什么區(qū)別嗎
上篇的B+樹結(jié)構(gòu)我們知道锥债,葉子節(jié)點(diǎn)存放著一行的數(shù)據(jù)叉谜,這個(gè)是區(qū)分兩者的重要特征旗吁,如圖所示,左邊的圖是InnoDB的主鍵索引和二級(jí)索引停局,右邊為MyISAM的索引很钓,我們可知,對(duì)于MyISAM而言董栽,葉結(jié)點(diǎn)包含索引字段值及指向數(shù)據(jù)頁(yè)數(shù)據(jù)行的邏輯指針码倦,也就是說表的數(shù)據(jù)和索引是分隔開的,主鍵索引和二級(jí)索引并無差
別锭碳,查找數(shù)據(jù)的時(shí)候需要根據(jù)索引存放的數(shù)據(jù)行指針進(jìn)一步查找袁稽。對(duì)于InnoDB而言,索引有主鍵索引和普通索引的分別擒抛,聚簇索引根據(jù)主鍵來構(gòu)建推汽,葉子節(jié)點(diǎn)存在這一行的數(shù)據(jù),普通索引存放這主鍵的以及構(gòu)成索引的字段歧沪,也就是說在select查找的時(shí)候歹撒,如果是用的主鍵索引,則無需回表查詢诊胞,可以直接返回所查的數(shù)據(jù)暖夭,如果使用的是普通索引查詢,如果查詢的字段恰好為字段本身撵孤,也無需回表查詢迈着,如果查詢的字段不在構(gòu)成索引字段本身內(nèi),則需要根據(jù)主鍵回表查詢其他的字段邪码。由此可見裕菠,對(duì)于mysql來說 (select *)
本身也是會(huì)影響查詢效率,最好是只查需要的字段霞扬,覆蓋索引糕韧,避免回表
下面分析一下常見的索引類型
主鍵和唯一索引
對(duì)于一個(gè)表來說枫振,唯一索引可以有多個(gè),但是只有一個(gè)主鍵萤彩。主鍵就是唯一索引粪滤,但是唯一索引不一定是主鍵,唯一索引可以為空雀扶,但是空值只能有一個(gè)杖小,主鍵不能為空,對(duì)于多列組成的唯一索引,需要保證具有唯一性聯(lián)合索引
聯(lián)合索引在日常數(shù)據(jù)庫(kù)使用的時(shí)候也是經(jīng)常被使用到的愚墓,我們以(a,b,c) 為例子構(gòu)建一個(gè)聯(lián)合索引予权,實(shí)際上構(gòu)建了(a),(a,b),(a,b,c)三個(gè)索引,聯(lián)合索引 有“最左前綴”原則浪册,遇到范圍查詢(>扫腺、<、between村象、like)就會(huì)停止匹配笆环。接下來就分析一下常見的幾個(gè)問題。
例如下表:建立(a,b,c)的索引
CREATE TABLE `test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`a` varchar(15) NOT NULL,
`b` varchar(15) NOT NULL,
`c` varchar(15) NOT NULL,
`d` varchar(15) NOT NULL,
PRIMARY KEY (`id`),
KEY `index_a_b_c` (`a`,`b`,`c`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
- 如果顛倒a厚者、b躁劣、c順序是否會(huì)使用到索引
EXPLAIN SELECT * FROM test WHERE c='test' AND a='test' AND b='test'
可見MySQL會(huì)自動(dòng)對(duì)查詢的列進(jìn)行調(diào)整,不影響索引的使用
- 如果放棄最左原則库菲,也就是不查a账忘,直接查詢b、c
EXPLAIN SELECT * FROM test WHERE c='test' AND b='test'
第二.png
說明不使用第一個(gè)查詢列的時(shí)候是無法觸發(fā)索引的
根據(jù)上面的結(jié)果我們現(xiàn)在反推一些查詢語句的時(shí)候應(yīng)該如何建立索引
SELECT * FROM test WHERE a > 1 and b = 2
如果上面這個(gè)查詢語句建立的是(a熙宇,b)的時(shí)候是只能使用到a索引鳖擒,如果是建立(b,a)的索引奇颠,MySQL的優(yōu)化器會(huì)幫我們調(diào)整败去,從而使用到索引
EXPLAIN SELECT * FROM test WHERE a IN (1,7,9) and b > 1
還是對(duì)(a,b)建立索引烈拒,因?yàn)镮N在這里可以視為等值引用圆裕,不會(huì)中止索引匹配,所以還是(a,b)
SELECT * FROM test WHERE a > 1 and b = 2 and c > 3;
對(duì)于上面的語句而言,建立(b,c)還是(b,a)都差不多荆几,因?yàn)闊o法全部都涉及到吓妆,所以需要看具體使用情況
- 隨便分析一個(gè)索引和排序的問題吧
EXPLAIN SELECT * FROM test WHERE a =1 ORDER BY b;
EXPLAIN SELECT * FROM test WHERE a >1 ORDER BY b;
上面建立了(a,b)的索引,當(dāng)a = 1的時(shí)候吨铸,b相對(duì)有序行拢,可以避免再次排序,而第二個(gè)語句是一個(gè)范圍查詢诞吱,這個(gè)范圍內(nèi)b值是無序的舟奠,沒有必要對(duì)(a,b)建立索引
共同進(jìn)步竭缝,學(xué)習(xí)分享
歡迎大家關(guān)注我的公眾號(hào)【寫代碼的小楊】,相關(guān)文章沼瘫、學(xué)習(xí)資料都會(huì)在里面更新抬纸,整理的資料也會(huì)放在里面。
覺得寫的還不錯(cuò)的就點(diǎn)個(gè)贊耿戚,加個(gè)關(guān)注唄湿故!點(diǎn)關(guān)注,不迷路膜蛔,持續(xù)更新L持怼!皂股!