MongoDB範圍查詢的索引優化
我們知道,MongoDB的索引是B-Tree結構的,和MySQL的索引非常類似。所以你應該聽過這樣的建議:建立索引的時候要考慮到sort操作,儘量把sort操作要用到的欄位放到你的索引後面。但是有的情況下,這樣做反而會使你的查詢效能更低。
問題
比如我們進行下面這樣的查詢:
db.collection.find({"country": "A"}).sort({"carsOwned": 1})
查詢條件是 {“country”: “A”},按 carsOwned 欄位的正序排序。所以索引就很好建了,直接建立 country , carsOwned 兩個欄位的聯合索引即可。像這樣:
db.collection.ensureIndex({"country": 1, "carsOwned": 1})
我們來看一個稍微複雜一點的查詢:
db.collection.find({"country": {"$in": ["A", "G"]}}).sort({"carsOwned": 1})
這回我們是要查詢 country 為 A 或者 G 的資料條目,結果同樣按 carsOwned 欄位排序。
如果我們還使用上面的索引,並且使用 explain() 分析一下這個查詢,就會發現在輸出中有一個 “scanAndOrder” : true 的欄位,並且 nscanned 的值可能會比想象中的大很多,甚至指定了 limit 也沒什麼效果。
原因
這是什麼原因呢,我們先看下面這張圖:
如上圖所未,左邊一個是按 {“country”: 1, “carsOwned”: 1} 的順序建立的索引。而右邊是按 {“carsOwned”: 1, ”country”: 1} 順序建立的索引。
如果我們執行上面的查詢,通過左邊的索引,我們需要將 country 值為A的(左圖的左邊一支)所有子節點以及country 值為G的(左圖的右邊一支)所有子節點都取也來。然後再對取出來的這些資料按 carsOwned 值進行一次排序操作。
所以說上面 explain 輸出了一個 “scanAndOrder” : true 的提示,就是說這次查詢,是先進行了scan獲取到資料,再進行了獨立的排序操作的。
那如果我們使用右邊的索引來做查詢,結果就不太一樣了。我們沒有將排序欄位放在最後,而是放在了前面,相反把篩選欄位放在了後面。那這樣的結果就是:我們會從值為1的節點開始遍歷(右圖的左邊一支),當發現有 country 值為 A 或 G 的,就直接放到結果集中。當完成指定數量(指定 limit 個數)的查詢後。我們就可以直接將結果返回了,因為這時候,所有的結果本身就是按 carsOwned 正序排列的。
對於上面的資料集,如果我們需要2條結果。我們通過左圖的索引需要掃描到4條記錄,然後對4條記錄進行排序才能返回結果。而右邊只需要我們掃描2條結果就能直接返回了(因為查詢的過程就是按需要的順序去遍歷索引的)。
所以,在有範圍查詢(包括$in, $gt, $lt 等等)的時候,其實刻意在後面追加排序索引通常是沒有效果的。因為在進行範圍查詢的過程中,我們得到的結果集本身並不是按追加的這個欄位來排的,還需要進行一次額外的排序才行。而在這種情況下,可能反序建立索引(排序欄位在前、範圍查詢欄位在後)反而會是一個比較優的選擇。當然,是否更優也和具體的資料集有關。
總結
總結一下,舉兩個栗子。
當查詢是:
db.test.find({a:1,b:2}).sort({c:1})
那麼直接建立 {a:1, b:1, c:1} 或者 {b:1, a:1, c:1} 的聯合索引即可。
如果查詢是:
db.test.find({a:1,b:{$in:[1,2]}}).sort({c:1})
那麼可能建立 {a:1, c:1, b:1} 的聯合索引會比較合適。當然,這裡只是提供了多一種思路,具體是否採用還是需要視你的資料情況而定。
相關文章
- 【索引】反向索引--條件 範圍查詢索引
- 【索引】反向索引--條件 範圍查詢(二)索引
- MongoDB之資料查詢(範圍運算)MongoDB
- 高效的SQL(Index-Organized Tables優化精確查詢和範圍查詢)SQLIndexZed優化
- mongodb索引及查詢優化分析MongoDB索引優化
- MySQL索引與查詢優化MySql索引優化
- 關於聯合索引,範圍查詢,時間列索引的幾個問題索引
- MongoDB慢查詢與索引MongoDB索引
- MySQL-效能優化-索引和查詢優化MySql優化索引
- MySQL 唯一索引範圍查詢鎖下一個記錄的理解MySql索引
- MYSQL DQL in 到底會不會走索引&in 範圍查詢引發的思考。MySql索引
- Oracle日期時間範圍查詢Oracle
- MongoDB的適用範圍MongoDB
- MySQL 索引及查詢優化總結MySql索引優化
- MySQL索引原理及慢查詢優化MySql索引優化
- 【oracle 效能優化】組合索引查詢。Oracle優化索引
- mysql效能優化-慢查詢分析、優化索引和配置MySql優化索引
- MongoDB索引優化詳解MongoDB索引優化
- msyql千萬級別查詢優化之索引優化索引
- MS SQL SERVER索引優化相關查詢SQLServer索引優化
- 《MySQL慢查詢優化》之SQL語句及索引優化MySql優化索引
- UPDATE查詢結果範圍內的資料
- MongoDB索引與優化詳解MongoDB索引優化
- 查詢中讓優化器使用複合索引優化索引
- MySQL索引的最左字首原理與查詢的相關優化MySql索引優化
- 優化-mysql子查詢索引失效問題解決優化MySql索引
- 使用點陣圖連線索引優化OLAP查詢索引優化
- 查詢優化優化
- MySQL 的查詢優化MySql優化
- mysql千萬級資料量根據索引優化查詢速度MySql索引優化
- 根據時間範圍呼叫gitLab介面查詢Gitlab
- mongodb異機做時間點恢復(基於時間範圍查詢匯出oplog)MongoDB
- 一文讀懂MySQL的索引結構及查詢優化MySql索引優化
- pgsql查詢優化之模糊查詢SQL優化
- Oracle in 查詢優化Oracle優化
- MySQL查詢優化MySql優化
- join 查詢優化優化
- HBase查詢優化優化