索引:如何在海量数据中快速查找某个数据?
轉(zhuǎn)自:https://blog.csdn.net/every__day/article/details/90763607
《數(shù)據(jù)結(jié)構(gòu)與算法之美》
前面講過MySQL數(shù)據(jù)庫索引實現(xiàn)原理,底層是依賴B+樹這種數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)的。那類似Redisp 這要的Key-Value數(shù)據(jù)庫中的索引,又是怎么實現(xiàn)的呢?底層依賴的又是什么數(shù)據(jù)結(jié)構(gòu)呢?
為什么需要索引?
在實際的軟件開發(fā)中,業(yè)務紛繁復雜,功能千變?nèi)f化,但是,萬變不離其宗。如果拋開業(yè)務和功能的外殼,其實它們的本質(zhì)都可以抽象為“對數(shù)據(jù)的存儲和計算”。對應到數(shù)據(jù)結(jié)構(gòu)和算法中,那“存儲”需要的就是數(shù)據(jù)結(jié)構(gòu),“計算”需要的就是算法。
對于存儲的需求,功能上無外乎增刪改查。這其實并不復雜。但是,一旦存儲的數(shù)據(jù)多了,那性能就成了這些系統(tǒng)要關(guān)注的重點,特別是在一些跟存儲相關(guān)的基礎(chǔ)系統(tǒng)(比如MySQL數(shù)據(jù)庫、分布式文件系統(tǒng)等)、中間件(比如消息中間件RocketMQ等)中。
“如何節(jié)省存儲空間、如何提高數(shù)據(jù)增刪改查的執(zhí)行效率”,這個問題就成了設(shè)計的重點。而這些系統(tǒng)的實現(xiàn),都離不開一個東西,那就是索引。不夸張的說,索引設(shè)計的好壞,直接決定了這些系統(tǒng)是否優(yōu)秀。
索引這個概念,非常好理解。你可以類比書籍的目錄來理解。如果沒有目錄,我們想要查找某個知識點的時候,就要一頁一頁的翻。通過目錄,我們就可以快速定位相關(guān)的知識點的頁數(shù),查找的速度也會有質(zhì)的提高。
索引的需求定義
索引的概念不難理解,在設(shè)計索引的過程中,需要考慮一些因素,換名話說,我們該如何定義清楚需求呢?
對于系統(tǒng)設(shè)計需求,我們一般可以從功能性需求和非功能性需求兩方面來分析。
1. 功能性需求
對于功能性需求大致要考慮以下幾點。
數(shù)據(jù)是格式化的還是非格式化數(shù)據(jù)?要構(gòu)建索引的原始數(shù)據(jù),類型很多。我把它分為兩類,一類是結(jié)構(gòu)化數(shù)據(jù),比如MySQL中的數(shù)據(jù);另一類是非結(jié)構(gòu)化數(shù)據(jù),比如搜索引擎中的網(wǎng)頁。對于非結(jié)構(gòu)化數(shù)據(jù),我們一般需要做預處理,提取出查詢關(guān)鍵詞,對關(guān)鍵詞構(gòu)建索引。
數(shù)據(jù)是靜態(tài)數(shù)據(jù)還是動態(tài)數(shù)據(jù)?如果原始是一組靜態(tài)數(shù)據(jù),也就是說,不會有數(shù)據(jù)的增加、刪除、更新操作,所以,我們在構(gòu)建索引的時候,只需要考慮查詢效率就可以了。這樣,索引的構(gòu)建就相對簡單些。不過,大部分情況下,我們都是對動態(tài)數(shù)據(jù)構(gòu)建索引,也就是說,我們不僅要考慮到索引的查詢效率,在原始數(shù)據(jù)更新時,我們還需要動態(tài)的更新索引。支持動態(tài)數(shù)據(jù)集合的索引,設(shè)計越來相對更復雜些。
索引是存儲在內(nèi)存還是硬盤?如果索引存儲在內(nèi)存中,那技術(shù)要求的速度肯定要比存儲的磁盤中的高。但是,如果原始數(shù)據(jù)量很大的情況下,對應的索引可能也會很大。這個時候,因為內(nèi)存有限,我們可能就不得不將索引存儲在硬盤中了。實際上,還有第三種情況,那就是一部分存儲在內(nèi)存,一部分存儲在磁盤,這樣就可以兼顧內(nèi)存消耗和查詢效率。
單值查找還是區(qū)間查找?所謂單值查找,也就是根據(jù)查詢關(guān)鍵詞等于某個值的數(shù)據(jù)。這種查詢需求最常見。所謂區(qū)間查找,就是查找關(guān)鍵詞處于某個區(qū)間值的所有數(shù)據(jù)。實際上,不同的應用場景,查詢的需求會多種多樣。
單關(guān)鍵詞查找還是多關(guān)鍵詞組合查找?比如,搜索引擎中構(gòu)建的索引,既要支持一個關(guān)鍵詞的查找,比如“數(shù)據(jù)結(jié)構(gòu)”,也要支持組合關(guān)鍵詞查找,比如“數(shù)據(jù)結(jié)構(gòu) AND算法”。對于單關(guān)鍵詞查找,索引構(gòu)建起來相對簡單些。對于多關(guān)鍵詞查找來說,要分多種情況。像MySQL這種結(jié)構(gòu)化數(shù)據(jù)的查詢需求,我們可以實現(xiàn)針對多個關(guān)鍵詞組合,建立索引;對于像搜索引擎這樣的非結(jié)構(gòu)數(shù)據(jù)的查詢需求,我們可以針對間個關(guān)鍵詞構(gòu)建索引,然后通過集合操作,比如求并集、求交集等,計算出多個關(guān)鍵詞組合的查詢結(jié)果。
實際上,不同的場景,不同的原始數(shù)據(jù),對于索引的需求也會千差萬別。
2.非功能性需求
不管是存儲在內(nèi)存中還是磁盤中,索引對存儲空間的消耗不能過大。如果存儲在內(nèi)存中,索引對占用存儲空間的限制就會非常苛刻。畢竟內(nèi)存空間非常有限,一個中間件啟動后就占用幾個GB的內(nèi)存,開發(fā)者顯然是無法接受的。如果存儲在硬盤中,那索引對占用存儲空間的限制,稍微會放寬一些。但是,我們也不能掉以輕心。因為,有時候,索引對存儲空間消耗會超過數(shù)據(jù)。
在考慮索引查詢效率的同時,我們還是考慮索引的維護成本。索引的目的是提高查詢效率,但是,基于動態(tài)數(shù)據(jù)集合構(gòu)建的索引,我們還要考慮到索引的維護成本。因為在原始數(shù)據(jù)動態(tài)增刪改的同時,我們也需要動態(tài)的更新索引。而索引的更新勢必會影響到增刪改的操作性能。
構(gòu)建索引常用的數(shù)據(jù)結(jié)構(gòu)有哪些?
實際上,常用來構(gòu)建索引的數(shù)據(jù)結(jié)構(gòu),就是我們之前講過的幾種支持動態(tài)數(shù)據(jù)集合的數(shù)據(jù)結(jié)構(gòu)。比如,散列表、紅黑樹、跳表、B+樹。除此之外,位圖、布隆過濾器可以作為輔助索引,有序數(shù)組可以用來對靜態(tài)數(shù)據(jù)構(gòu)建索引。
我們知道,散列表增刪改查操作的性能非常好,時間復雜度是O(1)。一些鍵值數(shù)據(jù)庫,比如Redis、Memcache,就是使用散列表來構(gòu)建索引的。這類索引,一般都構(gòu)建在內(nèi)存中。
紅黑樹作為一種常用的平衡二叉查找樹,數(shù)據(jù)插入、刪除、查找的時間復雜度是O(logn),也非常適合用來構(gòu)建內(nèi)存索引。Ext文件系統(tǒng)中,對磁盤塊的索引,用的就是紅黑樹。
B+ 樹比起紅黑樹來說,更加適合構(gòu)建存儲在磁盤的索引。B+樹是一個多叉樹,所以,以相同個數(shù)的數(shù)據(jù)構(gòu)建索引,B+樹的高度要低于紅黑樹。當借助索引查詢數(shù)據(jù)的時候,讀取B+樹索引,需要的磁盤IO次數(shù)更少。所以,大部分關(guān)系型數(shù)據(jù)庫的索引,比如MySQL、Oracle,都是用B+樹來實現(xiàn)的。
跳表也支持快速添加、刪除、查找數(shù)據(jù)。而且,我們通過靈活調(diào)整索引結(jié)點個數(shù)和數(shù)據(jù)個數(shù)之間的比例,可以很好的平衡對內(nèi)存的消耗及其查詢效率。Redis中的有序集合,就是用跳表來構(gòu)建的。
除了散列表、紅黑樹、B+樹、跳表之外,位圖和布隆過濾器這兩個數(shù)據(jù)結(jié)構(gòu),也可以用于索引中,輔助存儲在磁盤中的索引,加速數(shù)據(jù)查詢的效率。我們來看下,具體是怎么做的?
布隆過濾器有一定的判錯率。但是,我們可以規(guī)避它的短處,發(fā)揮它的長處。盡管對于判定存在的數(shù)據(jù),有可能并不存在,但是對于判定不存在的數(shù)據(jù),那肯定就不存在。而且,布隆過濾器還有一個更大的特點,那就是內(nèi)存占用非常少。我們可以針對數(shù)據(jù),構(gòu)建一個布隆過濾器,并且存儲在內(nèi)存中。當要查詢數(shù)據(jù)的時候,我們可以先通過布隆過濾器,判定是否存在。如果數(shù)據(jù)不存在,那我們就沒必要讀取磁盤中的索引了。對于數(shù)據(jù)不存在的情況,數(shù)據(jù)查詢就更加快速了。
實際上,有序數(shù)組也可以被作為索引。如果數(shù)據(jù)是靜態(tài)的,也就是不會插入、刪除、更新操作,那我們可以把數(shù)據(jù)的關(guān)鍵詞(查詢用的)抽取出來,組織成有序數(shù)組,然后利用二分查找算法來快速查找數(shù)據(jù)。
總結(jié)
以上是生活随笔為你收集整理的索引:如何在海量数据中快速查找某个数据?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 永辉生活如何预约购买茅台
- 下一篇: ExtJs桌面组件(DeskTop)