為什麼要有復合索引?

2021-09-25 17:46:45 字數 2762 閱讀 9474

要理解索引,你需要在腦中有個畫面,這裡建議想象一本食譜,不是普通食譜,而是5000頁的厚重食譜,包含各種場合、菜餚和季節的食譜。雖然這個食譜很全,但是它有個缺點就是它是亂序的,第一頁可能是魚香茄子,第3000頁是紅燒茄子。

這還不是很要緊,關鍵問題是這本食譜沒有索引!

下面是你要問自己的第乙個問題:如果沒有索引如何在食譜中找到糖醋排骨?唯一的選擇是一頁一頁翻過去,如果它在3892頁,你得要翻多少頁呀,最壞的情況是它在最後一頁,你就得把整本書都翻一遍。

解決辦法就是構建乙個索引。

我們可以想到多種查詢方法,其中食譜名稱可以作為乙個起點。如果建立乙個按食譜名稱排列列表,隨後是其所在頁碼,那麼就是按食譜名稱對書建立索引了。其中的條目可能是這樣的:

紅燒排骨 : 45

豬肉餃子 : 320

醬蘿蔔 : 199

現在只要知道食譜的名稱就能通過該索引快速找到書中的任意食譜了,如果你只希望通過這種方式來檢索食譜,那就已經完事兒了。

但這是不現實的,比方說,你還會希望根據你冰箱裡面的食材查詢食譜,或者是根據菜餚來進行查詢。針對這種情況,你需要更多的索引。

這就產生了第二個問題,只有乙個基於食譜名稱的索引,如何能找到所有的排骨相關的食譜呢?缺少合適的索引,你仍然需要翻閱整本食譜–5000頁。在根據食材或者菜餚進行檢索時都是如此。

為此我們需要構建另乙個索引,這次是對食材進行索引,在這個索引裡面按照字母順序排列食材,每個食材都指向所有包含它的食譜所在的頁碼。最基本的食材索引是這樣的

牛肉 : 301, 342, 785, 2310, 2456, 4310 ...

山藥 : 8, 20, 45, 78, 287, 1295, 4587 ...

豬肉 : 12, 124, 320, 890, 3719, ...

這是你希望的索引嗎?是不是很有用?

如果只是需要知道指定食材的食譜清單,這個索引就夠用了,但如果還希望在查詢時包含任何任意其他與與食譜相關的資訊,還是需要進行「掃瞄」–一旦知道牛肉的頁碼,你要翻到每一頁找到食譜的名字以及確定菜餚型別,雖然這比我們翻閱整本書要好,但是還遠遠不夠。

例如,一周前,你無意間在這本食譜裡面發現了乙個很棒的雞肉料理食譜,但是卻忘了它的名字,你很想找到它然後做給你心儀的漂亮小姐姐吃。目前為止,有兩個索引,乙個時食譜名稱的索引,另乙個是食材的索引。是否能將兩者結合起來,找到遺忘的雞肉食譜呢?

實際上,這是不可能的。如果從食譜名稱索引入手,但是卻不記得名字,檢索這個索引只比翻閱全書好一點點。從食材入手,則要檢查一系列頁碼,但是這些頁碼無法插入基於食譜名稱的索引。因此這種情況下只能使用乙個索引,本例中食材的索引要更有用一點。

通常認為乙個查詢裡面要查詢兩個字段,可以針對它們分離索引。有乙個現成的演算法:查詢每個索引裡匹配項的頁碼,針對同時匹配兩個索引的名單掃面它們頁碼的交集。這樣可以減少掃瞄的總數。一些資料庫實現了這個演算法,但mongodb中沒有。就算它實現了,使用復合索引來查詢兩個字段總是會比我剛才描述的演算法效率高。請記住每個查詢中資料庫只會使用乙個索引,如果要對多個字段進行查詢,請確保有這些欄位的符合索引。

那該怎麼辦?幸好我們有復合索引。

目前為止你建立的都是單鍵索引:它們只是對食譜的乙個鍵進行索引。現在要為整本食譜構建乙個新的索引,不同之處這次是要使用兩個鍵。類似的使用多個鍵的索引成為復合索引(compound index)。

該復合索引依次使用了食材和食譜名稱,可以這樣來標記它: 材料-食譜,其中的部分內容如下所示:

豬肉:

豬肉白菜燉粉條: 320

豬肉蛋捲: 3719

豬肉脯: 890

雞腿: 紅燒雞腿: 82

可樂雞腿: 3710

土豆燜雞腿: 2578

西紅柿 西紅柿炒雞蛋: 4827

西紅柿雞蛋湯: 2478

西紅柿牛腩: 489

這個索引的值對人是顯而易見的,現在可以根據食材進行查詢,大致定位要找的食譜,哪怕只是記得名稱的開頭部分。對機器而言同樣很有價值,不用掃瞄該食材的全部食譜名稱了。

需要注意的是復合索引的的順序是很有講究的,假設將上述索引翻轉為 食譜-材料,它能替代我們之前的索引嗎?

明顯不能!使用新索引,只要知道名稱,搜尋就一定會定位到乙個食譜,書中的一頁。如果是要查詢含有香蕉食材的豬肉食譜,那就可以確定不存在這個食譜。如果進行翻轉之後,我們就必須要知道食譜的名稱,在去找食材,但是現實情況往往是我們知道食材卻不知道食譜名稱。

現在整本食譜有三個索引:食譜食材食材-食譜,也就是說我們可以安全地去掉食材這個索引了。為什麼呢?

因為對某一食材的索引可以使用食材-食譜索引,如果你知道食材,可以便利該復合索引,獲得包含它的食譜的頁碼列表。

索引能夠顯著減少獲取文件所需的工作量。沒有合適的索引,實現查詢的唯一途徑就是線性掃瞄整個文件,直到滿足查詢條件為止。這通常就是掃瞄整個集合。

解析查詢時只會使用乙個單鍵索引(or是例外),對於包含多個鍵(比如食材和食譜)的查詢,包含這些鍵的復合索引能更好地解析查詢。

比如student表,對age和name都建立了索引,如果你查詢name=「zhangsan」 and age = 20,也只是會使用其中乙個索引

如果有食材-菜譜索引,可以去掉食材索引,也應該這麼做。更抽象一點,如果有乙個a-b的復合索引,那麼僅針對a的索引就是冗餘的。但是如果b本身就是乙個復合索引(b=c-d),那麼同時擁有a-b和a還是很有意義的。

符合索引裡鍵的順序也是很重要的。

為什麼要有cgroup

linux系統中經常有個需求就是希望能限制某個或者某些程序的分配資源。也就是能完成一組容器的概念,在這個容器中,有分配好的特定比例的cpu時間,io時間,可用記憶體大小等。於是就出現了cgroup的概念,cgroup就是controller group,最初由google的工程師提出,後來被整合進l...

為什麼要有多型?

include include using namespace std 岳不群 class yuebuqun virtual void fight virtual表7示修飾的乙個成員方法時乙個虛函式,和虛繼承含義不同 string kongfu 林平之類 class linpingzhi publi...

為什麼要有 hashCode

當你把物件加入 hashset 時,hashset 會先計算物件的 hashcode 值來判斷物件加入的位 置,同時也會與其他已經加入的物件的 hashcode 值作比較,如果沒有相符的hashcode,hashset會假設物件沒有重複出現。但是如果發現有相同 hashcode 值的物件,這時會呼叫...