如何通過索引提高數(shù)據(jù)庫檢索的效率

如何通過索引提高數(shù)據(jù)庫檢索的效率

這是前幾天同事做的技術(shù)分析,講的挺不錯,現(xiàn)在整理一下

本文中數(shù)據(jù)庫操作與數(shù)據(jù)庫工作原理描述,都是經(jīng)過簡化的,實際應(yīng)用中,數(shù)據(jù)庫本身也會提供各種優(yōu)化措施。

數(shù)據(jù)庫線性搜索

假設(shè)現(xiàn)在又一個幾百萬條數(shù)據(jù)的購物車銷售記錄表,表結(jié)構(gòu)類似下表

id userid productid dealdate promotions dealstate
1 10876 100003 14567776667 -9.5 成交
2 93772 188293 14566636777 -8 關(guān)閉

Q1: 查詢 userid = 100003 的用戶,所有購買記錄。

A1: 在沒有做任何優(yōu)化的情況下,數(shù)據(jù)庫需要從 id = 1 的記錄開始向下掃描,直到將整個?表掃描完畢,才可以檢索出所有?符合要求的記錄。?可想而知,當(dāng)表中記錄非常多的時候,需要?非常多的磁盤 I/O 才能完成此次查詢。在實際應(yīng)用中,例如 x 東用戶查詢自己的購買記錄這種需求,對服務(wù)器來說就是災(zāi)難啊。

使用索引提高查詢效率

使用?單個字段建立索引

回到 Q1 這個問題,如果我們在 userid 這個字段上建立索引,那么會產(chǎn)生一個 userid 到?記錄位置的映射。?這也是一個?表,在這個表中?查找某個 userid,就能夠找到所有符合該 userid ?的記錄在表中的位置,然后直接訪問這些位置讀取記錄就可以了。

使用多個字段建立索引

?Q2: 如果遇到一個購物達人,購物記錄有上萬條,通過 userid 這個索引查詢該用戶的所有搜索記錄,就?會產(chǎn)生上萬次磁盤 I/O,如果是機械硬盤,單單是尋道時間就?把這次查詢卡爆了,即使換 SSD,能夠服務(wù)的用戶?也是很有限的。

A2: ?遇到這種情況,我們可以將該用戶的購物記錄分頁,每次返回十幾條展示出來就可以了。向后翻頁的時候,可以從 offset 開始,再檢索出十幾條返回到前端展示。特別是移動端與桌面端?可能會跳到第10頁這種需求不同,向來都是上拉加載更多,是線性加載的,?對數(shù)據(jù)庫壓力就更小了。(PS. 跳轉(zhuǎn)到第幾頁這種需求,需要 count 數(shù)據(jù)的總數(shù),通常情況下,這個操作也需要將所有記錄讀取一遍,效率很低。)
這種需求下,一般會將購物記錄按照時間順序返回給用戶,我們只需要用 userid 和 dealdate 這兩個字段建立一個復(fù)合索引{userid,dealdate}就可以了。(建立索引時,指定 dealdate 按照降序排列)
檢索時,查找“近一月購物記錄”,只要按照時間檢索一些數(shù)據(jù)出來就可以了。

不應(yīng)該建立?什么樣的索引

如果?我們需要查詢成交狀態(tài),是不是可以?建立一個{dealstate}這樣的索引呢?
答案是,沒什么用。
如果檢索 dealstate = 成交 這樣的記錄,如果掃描整個表,需要檢索的記錄是 500?w 條。建立索引后,檢索的記錄也就減到 100w-200w 條。

這種優(yōu)化,并沒有數(shù)量級上的優(yōu)化效果,還需要占用大量空間,這種“優(yōu)化”一般認為是沒有意義的。

對于值為 bool 型或 enum? 型的字段,通常不建立索引。

建立索引的兩種原理

索引到數(shù)據(jù)映射一般有兩種實現(xiàn)方式,一種是 hash?,這個沒有排序的能力,另一種是? B 樹或 B+ 樹,這個有排序的能力。

如何快速從索引中檢索相應(yīng)的值

通常情況下,會選擇 B 樹或者 B+ 樹實現(xiàn)索引,以獲得排序的能力。

B+ 樹

從 B+ 樹的數(shù)據(jù)結(jié)構(gòu)來看,?解決 ?Q2? 這個問題,例如要檢索上個月購物記錄,只要 logN 的時間就能查詢到相應(yīng)的記錄。

B+ 樹在 logN 時間內(nèi)就可以完成查找

?并且從上圖可以看到,B+ 樹的各個節(jié)點之間,都通過指針進行連接,從當(dāng)前指向的數(shù)據(jù)出發(fā),向后查找數(shù)據(jù)是非常方便和快速的。能完美的實現(xiàn)上拉加載更多這種需求。

應(yīng)該如何建立復(fù)合索引

如果對本文開頭的表,建立一個復(fù)合索引,同時查詢購買時間、購物折扣等,可以?這樣建立復(fù)合索引。
{ productid(升序),promotions(升序), dealdate(降序)}
這里,雖然對 productid 進行排序沒有現(xiàn)實意義,但是在計算機看來,依然是可以排序的。
在建立? B+ 樹時,先比較 productid,再比較 promotions,最后比較? dealdate,并且按照比較結(jié)果?生成一顆 B+ 樹。

那么查找的時候,如果檢索的內(nèi)容是:{productid},索引是有效的。

如果?檢索的內(nèi)容是:{ productid(升序)、dealdate(降序)} 那么索引也是有效的,比較的時候,promotions 不比較(永遠==)就可以了。

如果檢索的內(nèi)容是:{ productid(升序)、 dealdate(降序)、promotions(升序)} 這時候,索引就無效了。因為此時的比較條件,與生存索引時的比較條件不一致(生成索引時,productid 相同的情況下,比較 promotions 的大小,此時 productid 相同的情況下,比較 dealdate 的大小。)

如果檢索的內(nèi)容是:{ productid(升序)、dealdate(升序)} 索引也是無效的。此時比較的條件,也與索引生成時不一致。

從上文就可以看出,建立數(shù)據(jù)庫索引時,就要考慮檢索條件才行

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容