2012-07-10 72 views
0

我的數據集由包含具有整數數組的字段的文檔組成。當我計算其字段包含某些範圍內的元素的對象時,似乎索引掃描性能會隨着indexBounds值更高而降低(但該範圍掃描的值相同)。搜索更高值時索引掃描性能下降

測試數據:

for (var i = 0; i < 100000; i++) db.foo.insert({tts:(function(){var val = [];for(var j = 0; j < 100; j++) {val[j] = j} return val;})()}); 
db.foo.ensureIndex({tts:1}); 

查詢:當請求的範圍內有最高的界限

> db.foo.find({tts:{$elemMatch:{$gte:10, $lte:10}}}).explain() 
{ 
    "cursor" : "BtreeCursor tts_1", 
    "isMultiKey" : true, 
    "n" : 100000, 
    "nscannedObjects" : 100000, 
    "nscanned" : 100000, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 1, 
    "nChunkSkips" : 0, 
    "millis" : 313, 
    "indexBounds" : { 
     "tts" : [ 
      [ 
       10, 
       10 
      ] 
     ] 
    }, 
    "server" : "localhost:27017" 
} 
> db.foo.find({tts:{$elemMatch:{$gte:90, $lte:90}}}).explain() 
{ 
    "cursor" : "BtreeCursor tts_1", 
    "isMultiKey" : true, 
    "n" : 100000, 
    "nscannedObjects" : 100000, 
    "nscanned" : 100000, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 1, 
    "nChunkSkips" : 0, 
    "millis" : 1286, 
    "indexBounds" : { 
     "tts" : [ 
      [ 
       90, 
       90 
      ] 
     ] 
    }, 
    "server" : "localhost:27017" 
} 

其實我有近200個值在這個領域和查詢起牀慢10倍。 (在字段中的每個值屬於獨特的範圍內,所有的範圍選擇對象(100000相同量),查詢僅針對此子範圍進行範圍)

收集統計:

> db.foo.stats() 
{ 
    "ns" : "test.foo", 
    "count" : 100000, 
    "size" : 122400128, 
    "avgObjSize" : 1224.00128, 
    "storageSize" : 140763136, 
    "numExtents" : 12, 
    "nindexes" : 2, 
    "lastExtentSize" : 40071168, 
    "paddingFactor" : 1, 
    "systemFlags" : 1, 
    "userFlags" : 0, 
    "totalIndexSize" : 254845920, 
    "indexSizes" : { 
     "_id_" : 3262224, 
     "tts_1" : 251583696 
    }, 
    "ok" : 1 
} 

是否有解決這個問題的方法?

謝謝。

+0

您使用的是什麼版本的MongoDB? – Stennie 2012-07-11 05:50:00

+0

2.1.2/2.1.3-pre- – 2012-07-11 07:23:30

回答

0

Mongo能夠使用該索引來確定每個文檔中都存在與$ lte和$ gte條件相匹配的元素。 $ elemmatch要求單個元素匹配兩個條件,所以mongo掃描每個文檔(和子數組)以確定這樣的元素是否存在。對於較大的值,mongo必須將90個元素掃描到每個數組中,而不是僅在前10個元素中查找匹配元素。因此,對長陣列結束的匹配元素的查詢將花費更長的時間。

請注意,如果你扭轉陣列,行爲相反:

for (var i = 0; i < 100000; i++) db.foo.insert({tts:(function(){var val = [];for(var j = 100; j >= 0; j--) {val[j] = j} return val;})()}); 

它看起來像這樣可能與https://jira.mongodb.org/browse/SERVER-6002。使用最新的開發版本可能會以穩定性爲代價解決問題。

+0

它似乎是這樣,但看着索引元素的總數(10000000 = 100 * 100000)我認爲每個數組元素被索引爲一個單獨的值,應該只允許掃描在[link]的評論中描述的請求範圍內的元素(https://jira.mongodb.org/browse/SERVER-4180?focusedCommentId=131489&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel #comment-131489) – 2012-07-11 07:32:06

+0

4180似乎解決了掃描太多索引(錯誤邊界)的問題,但似乎沒有改變關於檢查單個匹配元素的每個文檔的行爲。在你的情況下,索引界限被正確選擇,但它們匹配集合中的每個文檔,所以mongo仍然掃描每個文檔。如果只有少數文檔與查詢匹配,則性能下降應該可以忽略不計。 – narced133 2012-07-11 18:58:00

+0

感謝您的回答。目前還不清楚爲什麼當索引中找到所有必要的元素時,mongo應該掃描對象。儘管如此,爲了解決這個問題,我只是將我的大數組分割成小數組,並將它們保存到不同的字段中。 – 2012-07-13 17:08:15