数据库索引:引入
數(shù)據(jù)庫(kù)索引的通俗理解
為什么需要索引?
「索引就像書(shū)的目錄,通過(guò)書(shū)的目錄就準(zhǔn)確的定位到了書(shū)籍具體的內(nèi)容」,
數(shù)據(jù)在磁盤(pán)上是以塊的形式存儲(chǔ)的。為確保對(duì)磁盤(pán)操作的原子性,訪問(wèn)數(shù)據(jù)的時(shí)候會(huì)一并訪問(wèn)所有數(shù)據(jù)塊。磁盤(pán)上的這些數(shù)據(jù)塊與鏈表類(lèi)似,即它們都包含一個(gè)數(shù)據(jù)段和一個(gè)指針,指針指向下一個(gè)節(jié)點(diǎn)(數(shù)據(jù)塊)的內(nèi)存地址,而且它們都不需要連續(xù)存儲(chǔ)(即邏輯上相鄰的數(shù)據(jù)塊在物理上可以相隔很遠(yuǎn))。
舉個(gè)例子來(lái)講,我們有一個(gè)數(shù)據(jù)表User.為了簡(jiǎn)便,這個(gè)表沒(méi)有主鍵。
?
| Identity | Name | Age | Grade |
| 1 | Robin | 28 | 90 |
| 5 | Lilei | 26 | 60 |
| 3 | Hanmei | 25 | 50 |
| 4 | Lucy | 27 | 66 |
| 2 | Lily | 29 | 80 |
?
雖然這些數(shù)據(jù)都存在于一個(gè)User表中,但是物理上,這些數(shù)據(jù)可能存儲(chǔ)在分散的數(shù)據(jù)塊中。
查找Lily這個(gè)人的信息,?已知Lily的Identity為2,?select* fromUser where?Identity= 2.
在查找的時(shí)候,首先找到這個(gè)表的第一條記錄所在的數(shù)據(jù)庫(kù)地址,然后發(fā)現(xiàn)Identity為1,并不是所需要的值,然后在這個(gè)數(shù)據(jù)庫(kù)的底端,找到了下一個(gè)數(shù)據(jù)塊的地址。(這個(gè)類(lèi)似于鏈表),如此一來(lái),查詢了5次才找到了所需要的值。(為了簡(jiǎn)單起見(jiàn),我們考慮Identity不能有重復(fù)值)
?
為了加快搜索速度,這里就出現(xiàn)了索引。索引是對(duì)某個(gè)字段進(jìn)行排序的一種方式。對(duì)表中的某個(gè)字段建立索引會(huì)創(chuàng)建另一種數(shù)據(jù)結(jié)構(gòu),其中保存著字段的值,每個(gè)值又指向與它相關(guān)的記錄。這種索引的數(shù)據(jù)結(jié)構(gòu)是經(jīng)過(guò)排序的,因而可以對(duì)其執(zhí)行二分查找。
?
對(duì)上個(gè)表的Identity字段進(jìn)行索引,就是在數(shù)據(jù)庫(kù)存儲(chǔ)空間上創(chuàng)建一塊專(zhuān)用的控件,把User表的所有的Identity字段的值拿出來(lái)放到這里,并且對(duì)這些值進(jìn)行排序,并且每個(gè)值都攜帶著這個(gè)Identity對(duì)應(yīng)的行所在數(shù)據(jù)塊的地址。因?yàn)镮dentity是進(jìn)過(guò)排序的,按照一定的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)的,所以數(shù)據(jù)庫(kù)引擎在查找的時(shí)候,比如說(shuō)查找identity為5,引擎就會(huì)計(jì)算,5大概在整個(gè)排序結(jié)構(gòu)的大致地方,然后到那里去拿出這個(gè)值看看是不是,不是的話就再次相應(yīng)的向左或者向右移動(dòng)去尋找。(這里用到的知識(shí)都是大學(xué)時(shí)候的數(shù)據(jù)結(jié)構(gòu)的知識(shí),二分法查找,相對(duì)于毫無(wú)頭緒的一個(gè)一個(gè)的查找,二分法的查找速度明顯的提高,達(dá)到了log2 N,其實(shí)這有多快我也不明白,反正就記得當(dāng)時(shí)學(xué)的時(shí)候,確實(shí)是比一般查找快多了。)
?
通俗的來(lái)講,就是根據(jù)你指定的列,建立一個(gè)遵循一定數(shù)據(jù)結(jié)構(gòu)的區(qū)域,這些區(qū)域可以快速定位到相應(yīng)數(shù)據(jù)庫(kù)字段所在的磁盤(pán)地址。
索引的好處是特別明顯的,那就是大大的提高了查詢的速度。但是相對(duì)應(yīng)的也帶來(lái)了一些不好的地方。
第一,創(chuàng)建索引和維護(hù)索引要耗費(fèi)時(shí)間,這種時(shí)間隨著數(shù)據(jù)量的增加而增加。
第二,索引需要占物理空間,除了數(shù)據(jù)表占數(shù)據(jù)空間之外,每一個(gè)索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會(huì)更大。
第三,當(dāng)對(duì)表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時(shí)候,索引也要?jiǎng)討B(tài)的維護(hù),這樣就降低了數(shù)據(jù)的維護(hù)速度。
最后還有一點(diǎn)需要注意的是,我們?cè)跀?shù)據(jù)庫(kù)上對(duì)于某個(gè)字段建立了索引,那么什么情況下才走索引呢?
?
比如?select * from User where?Identity= 2?這條語(yǔ)句,是走索引查詢的。因?yàn)槭欠褡咚饕Q于這條查詢語(yǔ)句的where子句。數(shù)據(jù)庫(kù)引擎發(fā)現(xiàn)你的where語(yǔ)句中有identity,那么就會(huì)從identity的索引數(shù)據(jù)結(jié)構(gòu)中進(jìn)行檢索。曾經(jīng)看到有人說(shuō)select *會(huì)降低檢索速度,這個(gè)跟索引沒(méi)關(guān)系,select *?降低檢索速度,是因?yàn)閺臄?shù)據(jù)庫(kù)服務(wù)器端到客戶端的網(wǎng)絡(luò)傳輸是有時(shí)間的,select *?中難免包含著不必要的字段,所以傳輸起來(lái)會(huì)比較慢。
上述講到了存儲(chǔ)索引用的是某種數(shù)據(jù)結(jié)構(gòu)類(lèi)型,接下來(lái)將說(shuō)一下具體索引的存儲(chǔ)用到了什么數(shù)據(jù)結(jié)構(gòu)的類(lèi)型:
索引原理必須清楚一種數(shù)據(jù)結(jié)構(gòu)「平衡樹(shù)」(非二叉),也就是b tree或者 b+tree,重要的事情說(shuō)三遍:“平衡樹(shù),平衡樹(shù),平衡樹(shù)”。當(dāng)然,有的數(shù)據(jù)庫(kù)也使用哈希桶作用索引的數(shù)據(jù)結(jié)構(gòu),然而,主流的RDBMS都是把平衡樹(shù)當(dāng)做數(shù)據(jù)表默認(rèn)的索引數(shù)據(jù)結(jié)構(gòu)的。
下一節(jié)詳細(xì)講解索引的底層數(shù)據(jù)結(jié)構(gòu)?
總結(jié)
- 上一篇: Statement和PraparedSt
- 下一篇: MYSQL: MERGE引擎实现多分表的