使用索引是提高數(shù)據(jù)庫(kù)查詢效率的主要方式,下面從索引結(jié)構(gòu),索引類型,索引操作,命中索引幾個(gè)方面來(lái)介紹索引。
一、索引結(jié)構(gòu)
mysql5.5以上的默認(rèn)存儲(chǔ)引擎innodb,只顯式支持BTree( 事實(shí)上從數(shù)據(jù)結(jié)構(gòu)上來(lái)講是B+樹(shù),mysql稱之為BTree)索引,對(duì)于頻繁訪問(wèn)的表,innodb會(huì)建立自適應(yīng)hash索引,
即在B樹(shù)索引基礎(chǔ)上建立hash索引,可以顯著提高查找效率,用戶是無(wú)法自己指定的,除此之外還有Hash索引和全文索引(fullText索引)。?
BTree索引?
BTree,顧名思義,就是所有的索引節(jié)點(diǎn)都按照balance tree的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)。BTree結(jié)構(gòu)可以顯著減少定位記錄時(shí)所經(jīng)歷的中間過(guò)程,從而加快存取速度。
Btree中,每個(gè)結(jié)點(diǎn)包含:
1、本結(jié)點(diǎn)所含關(guān)鍵字的個(gè)數(shù);
2、指向父結(jié)點(diǎn)的指針;
3、關(guān)鍵字;
4、指向子結(jié)點(diǎn)的指針;
更詳細(xì)的B+樹(shù)介紹參考https://www.cnblogs.com/yangecnu/p/Introduce-B-Tree-and-B-Plus-Tree.html
Hash索引?
Hash 索引由于使用了hash表結(jié)構(gòu),其檢索效率很高,索引的檢索可以一次定位,不像B+樹(shù)索引需要從根節(jié)點(diǎn)到枝節(jié)點(diǎn),
所以 Hash 索引的查詢效率要遠(yuǎn)高于 B+樹(shù) 索引。但是,Hash索引的使用范圍非常有限。
? ? 1.在MySQL中,只有HEAP/MEMORY引擎表才能支持哈希索引,InnoDB引擎的自適應(yīng)哈希索引(adaptive hash index)不
? ?能在創(chuàng)建索引時(shí)指定。
? ?2.Hash索引僅支持=,>=,<=這幾種條件運(yùn)算,不支持排序,范圍內(nèi)查找,like等查詢。
? ?3.Hash索引不支持組合索引中部分索引的查找。
? ?4.當(dāng)Hash值重復(fù)較多時(shí),索引速度可能不如BTree索引。
FullText索引
Full-text索引就是我們常說(shuō)的全文索引,他的存儲(chǔ)結(jié)構(gòu)也是Btree。主要是為了解決在我們需要用like查詢的低效問(wèn)題。
只能解決’xxx%’的like查詢。如:字段數(shù)據(jù)為ABCDE,索引建立為A、AB、ABC、ABCD、ABCDE五個(gè)。
二、索引類型
索引一般有:普通索引,唯一索引,復(fù)合索引這幾種類型。
唯一索引:唯一索引要求字段中不會(huì)出現(xiàn)重復(fù)數(shù)據(jù)。
復(fù)合索引:將多個(gè)字段組合起來(lái)作為索引,必須使用到該索引中的第一個(gè)字段作為條件時(shí)才能保證系統(tǒng)使用該索引,否則該索引將不會(huì)被使用。
三、索引操作
建立索引:
createindex索引名on表名(索引字段名)
建立唯一索引:
createuniqueindex索引名on表名(索引字段名)
建立復(fù)合索引:
createindex索引名on表名(索引字段名1,索引字段名2...)
查看表中索引:
showindexfrom表名
刪除索引:
dropindex索引名on表名
查看索引是否命中
Mysql:當(dāng)結(jié)果的type為 index時(shí)索引命中
explain+sql語(yǔ)句
Oracle:
explainplanfor+sql語(yǔ)句
四、命中索引
1.避免判斷null值
應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
selectidfromtwherenumisnull
可以在num上設(shè)置默認(rèn)值0,確保表中num列沒(méi)有null值,然后這樣查詢:
selectidfromtwherenum=0
2. 避免不等值判斷
應(yīng)盡量避免在where子句中使用!=或<>操作符,否則引擎將放棄使用索引而進(jìn)行全表掃描。
3.避免使用or邏輯
應(yīng)盡量避免在where子句中使用 or 來(lái)連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,
selectidfromtwherenum=1ornum=2
可以使用union all來(lái)進(jìn)行查詢來(lái)命中索引如:
selectidfromtwherenum=1 unionall selectidfromtwherenum=2
4 .慎用in和not in邏輯
in和 not in 也要慎用,否則會(huì)導(dǎo)致全表掃描,如:
selectidfromt1wherenumin(selectidfromt2whereid>10)
此時(shí)外層查詢會(huì)全表掃描,不使用索引。可以修改為:
selectidfromt1,(selectidfromt1whereid>10)t2wheret1.id=t2.id
此時(shí)索引被使用,可以明顯提升查詢效率。
5.注意模糊查詢
下面的查詢也將導(dǎo)致全表掃描:
selectidfromtwherenamelike'%abc%'
不要在like條件左邊加'%',這樣不會(huì)走索引模糊查詢?nèi)绻潜匾獥l件時(shí),可以使用
selectidfromtwherenamelike'abc%'
來(lái)實(shí)現(xiàn)模糊查詢,此時(shí)索引將被使用。如果頭匹配是必要的,可以使用elasticsearch等全文搜索引擎。
6.避免查詢條件中字段計(jì)算
應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
selectidfromtwherenum/2=100
應(yīng)改為:
selectidfromtwherenum=100*2
7.避免查詢條件中對(duì)字段進(jìn)行函數(shù)操作
應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
selectidfromtwheresubstring(name,1,3)='abc'
name以abc開(kāi)頭的id
應(yīng)改為:
selectidfromtwherenamelike'abc%'
8. “=”左邊避免表達(dá)式運(yùn)算
不要在where子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無(wú)法正確使用索引。
9.組合索引使用
在使用索引字段作為條件時(shí),如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個(gè)字段作為條件時(shí)才能保證系統(tǒng)使用該索引,否則該索引將不會(huì)被使用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。
10exists
很多時(shí)候用exists代替 in 是一個(gè)好的選擇:
selectnumfromawherenumin(selectnumfromb)
用下面的語(yǔ)句替換:
selectnumfromawhereexists(select1frombwherenum=a.num)