為什么索引能提高查詢速度
MySQL 的基本存儲(chǔ)結(jié)構(gòu)
MySQL的基本存儲(chǔ)結(jié)構(gòu)是頁(記錄都存在頁里邊):
- 各個(gè)數(shù)據(jù)頁可以組成一個(gè)雙向鏈表
- 每個(gè)數(shù)據(jù)頁中的記錄又可以組成一個(gè)單向鏈表
- 每個(gè)數(shù)據(jù)頁都會(huì)為存儲(chǔ)在它里邊兒的記錄生成一個(gè)頁目錄汰蜘,在通過主鍵查找某條記錄的時(shí)候可以在頁目錄中使用二分法快速定位到對(duì)應(yīng)的槽,然后再遍歷該槽對(duì)應(yīng)分組中的記錄即可快速找到指定的記錄
- 以其他列(非主鍵)作為搜索條件:只能從最小記錄開始依次遍歷單鏈表中的每條記錄宪彩。
所以說对竣,如果我們寫select * from user where indexname = 'xxx'這樣沒有進(jìn)行任何優(yōu)化的sql語句氏身,默認(rèn)會(huì)這樣做:
- 定位到記錄所在的頁:需要遍歷雙向鏈表床估,找到所在的頁
- 從所在的頁內(nèi)中查找相應(yīng)的記錄:由于不是根據(jù)主鍵查詢雇寇,只能遍歷所在頁的單鏈表了
很明顯,在數(shù)據(jù)量很大的情況下這樣查找會(huì)很慢虽另!這樣的時(shí)間復(fù)雜度為O(n)暂刘。
使用索引之后
索引做了些什么可以讓我們查詢加快速度呢?其實(shí)就是將無序的數(shù)據(jù)變成有序(相對(duì)):
要找到id為8的記錄簡(jiǎn)要步驟:
很明顯的是:沒有用索引我們是需要遍歷雙向鏈表來定位對(duì)應(yīng)的頁捂刺,現(xiàn)在通過 “目錄” 就可以很快地定位到對(duì)應(yīng)的頁上了Rゼ稹(二分查找,時(shí)間復(fù)雜度近似為O(logn))
其實(shí)底層結(jié)構(gòu)就是B+樹族展,B+樹作為樹的一種實(shí)現(xiàn)森缠,能夠讓我們很快地查找出對(duì)應(yīng)的記錄。
最左前綴原則
MySQL中的索引可以以一定順序引用多列仪缸,這種索引叫作聯(lián)合索引辅鲸。如User表的name和city加聯(lián)合索引就是(name,city)o而最左前綴原則指的是,如果查詢的時(shí)候查詢條件精確匹配索引的左邊連續(xù)一列或幾列腹殿,則此列就可以被用到。如下:
select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
select * from user where city=xx; // 無法命中索引
這里需要注意的是例书,查詢的時(shí)候如果兩個(gè)條件都用上了锣尉,但是順序不同,如 city= xx and name =xx
决采,那么現(xiàn)在的查詢引擎會(huì)自動(dòng)優(yōu)化為匹配聯(lián)合索引的順序自沧,這樣是能夠命中索引的.
由于最左前綴原則,在創(chuàng)建聯(lián)合索引時(shí),索引字段的順序需要考慮字段值去重之后的個(gè)數(shù)拇厢,較多的放前面爱谁。ORDERBY子句也遵循此規(guī)則。
注意避免冗余索引
冗余索引指的是索引的功能相同孝偎,能夠命中 就肯定能命中 访敌,那么 就是冗余索引如(name,city )和(name )這兩個(gè)索引就是冗余索引,能夠命中后者的查詢肯定是能夠命中前者的 在大多數(shù)情況下衣盾,都應(yīng)該盡量擴(kuò)展已有的索引而不是創(chuàng)建新索引寺旺。
MySQLS.7 版本后,可以通過查詢 sys 庫的 schemal_r dundant_indexes
表來查看冗余索引
添加索引
1.添加PRIMARY KEY(主鍵索引)
ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` )
2.添加UNIQUE(唯一索引)
ALTER TABLE `table_name` ADD UNIQUE ( `column` )
3.添加INDEX(普通索引)
ALTER TABLE `table_name` ADD INDEX index_name ( `column` )
4.添加FULLTEXT(全文索引)
ALTER TABLE `table_name` ADD FULLTEXT ( `column`)
5.添加多列索引
ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )