MongoDB范圍查詢的索引優(yōu)化
我們知道,MongoDB的索引是B-Tree結(jié)構(gòu)的,和MySQL的索引非常類似。所以你應(yīng)該聽過這樣的建議:創(chuàng)建索引的時(shí)候要考慮到sort操作,盡量把sort操作要用到的字段放到你的索引后面。但是有的情況下,這樣做反而會(huì)使你的查詢性能更低。
問題
比如我們進(jìn)行下面這樣的查詢:
- db.collection.find({"country": "A"}).sort({"carsOwned": 1})
查詢條件是 {“country”: “A”},按 carsOwned 字段的正序排序。所以索引就很好建了,直接建立 country , carsOwned 兩個(gè)字段的聯(lián)合索引即可。像這樣:
- db.collection.ensureIndex({"country": 1, "carsOwned": 1})
我們來看一個(gè)稍微復(fù)雜一點(diǎn)的查詢:
- db.collection.find({"country": {"$in": ["A", "G"]}}).sort({"carsOwned": 1})
這回我們是要查詢 country 為 A 或者 G 的數(shù)據(jù)條目,結(jié)果同樣按 carsOwned 字段排序。
如果我們還使用上面的索引,并且使用 explain() 分析一下這個(gè)查詢,就會(huì)發(fā)現(xiàn)在輸出中有一個(gè)“scanAndOrder” : true 的字段,并且 nscanned 的值可能會(huì)比想象中的大很多,甚至指定了 limit 也沒什么效果。
原因
這是什么原因呢,我們先看下面這張圖:
如上圖所未,左邊一個(gè)是按 {“country”: 1, “carsOwned”: 1} 的順序建立的索引。而右邊是按{“carsOwned”: 1, ”country”: 1} 順序建立的索引。
如果我們執(zhí)行上面的查詢,通過左邊的索引,我們需要將 country 值為A的(左圖的左邊一支)所有子節(jié)點(diǎn)以及country 值為G的(左圖的右邊一支)所有子節(jié)點(diǎn)都取也來。然后再對(duì)取出來的這些數(shù)據(jù)按 carsOwned 值進(jìn)行一次排序操作。
所以說上面 explain 輸出了一個(gè) “scanAndOrder” : true 的提示,就是說這次查詢,是先進(jìn)行了scan獲取到數(shù)據(jù),再進(jìn)行了獨(dú)立的排序操作的。
那如果我們使用右邊的索引來做查詢,結(jié)果就不太一樣了。我們沒有將排序字段放在***,而是放在了前面,相反把篩選字段放在了后面。那這樣的結(jié)果就是:我們會(huì)從值為1的節(jié)點(diǎn)開始遍歷(右圖的左邊一支),當(dāng)發(fā)現(xiàn)有 country 值為 A 或 G 的,就直接放到結(jié)果集中。當(dāng)完成指定數(shù)量(指定 limit 個(gè)數(shù))的查找后。我們就可以直接將結(jié)果返回了,因?yàn)檫@時(shí)候,所有的結(jié)果本身就是按 carsOwned 正序排列的。
對(duì)于上面的數(shù)據(jù)集,如果我們需要2條結(jié)果。我們通過左圖的索引需要掃描到4條記錄,然后對(duì)4條記錄進(jìn)行排序才能返回結(jié)果。而右邊只需要我們掃描2條結(jié)果就能直接返回了(因?yàn)椴樵兊倪^程就是按需要的順序去遍歷索引的)。
所以,在有范圍查詢(包括$in, $gt, $lt 等等)的時(shí)候,其實(shí)刻意在后面追加排序索引通常是沒有效果的。因?yàn)樵谶M(jìn)行范圍查詢的過程中,我們得到的結(jié)果集本身并不是按追加的這個(gè)字段來排的,還需要進(jìn)行一次額外的排序才行。而在這種情況下,可能反序建立索引(排序字段在前、范圍查詢字段在后)反而會(huì)是一個(gè)比較優(yōu)的選擇。當(dāng)然,是否更優(yōu)也和具體的數(shù)據(jù)集有關(guān)。
總結(jié)
總結(jié)一下,舉兩個(gè)栗子。
當(dāng)查詢是:
- db.test.find({a:1,b:2}).sort({c:1})
那么直接建立 {a:1, b:1, c:1} 或者 {b:1, a:1, c:1} 的聯(lián)合索引即可。
如果查詢是:
- db.test.find({a:1,b:{$in:[1,2]}}).sort({c:1})
那么可能建立 {a:1, c:1, b:1} 的聯(lián)合索引會(huì)比較合適。當(dāng)然,這里只是提供了多一種思路,具體是否采用還是需要視你的數(shù)據(jù)情況而定。
原文鏈接:http://blog.nosqlfan.com/html/4117.html
【編輯推薦】
- 先睹為快:甲骨文NoSQL數(shù)據(jù)庫(kù)
- 八種主流NoSQL數(shù)據(jù)庫(kù)系統(tǒng)對(duì)比
- 解讀NoSQL數(shù)據(jù)庫(kù)的四大家族
- NoSQL在企業(yè)中的發(fā)展歷程
- 一個(gè)初創(chuàng)公司是否適用NoSQL引發(fā)的探討