2011-11-09 99 views
2

我有一個超過500萬個項目的MondoDB集合。每個項目都有一個包含整數值的「開始」和「結束」字段。搜索MongoDB中兩個項目字段之間的值的記錄

項目沒有重疊的開始和結束。

例如這將是無效

{start:100, end:200} 
{start:150, end:250} 

我試圖找到其中一個給定的值是開始和結束

start <= VALUE <= end 

下面的查詢工作之間的項目,但它需要5至15秒返回

db.blocks.find({ "start" : { $lt : 3232235521 }, "end" :{ $gt : 3232235521 }}).limit(1); 

我已經添加了測試以下指標用很少的改善

db.blocks.ensureIndex({start:1}); 
db.blocks.ensureIndex({end:1}); 

//also a compounded one 
db.blocks.ensureIndex({start:1,end:1}); 

**在查詢結果中編輯**

解釋的結果():

> db.blocks.find({ "start" : { $lt : 3232235521 }, "end" :{ $gt : 3232235521 }}).limit(1).explain(); 

{ 
     "cursor" : "BtreeCursor end_1", 
     "nscanned" : 1160982, 
     "nscannedObjects" : 1160982, 
     "n" : 0, 
     "millis" : 5779, 
     "nYields" : 0, 
     "nChunkSkips" : 0, 
     "isMultiKey" : false, 
     "indexOnly" : false, 
     "indexBounds" : { 
       "end" : [ 
         [ 
           3232235521, 
           1.7976931348623157e+308 
         ] 
       ] 
     } 
} 

什麼將加速這一特定查詢了最好的方法呢?

+0

您是否嘗試運行explain命令以查看查詢的nscanned編號?這可能是因爲你的查詢標準是爲''start'找到合格的文件,然後找到'end',反之亦然。 Btw是固定的間隔,例如0-99,100-199?或變量? – DhruvPathak

+0

我認爲你的東西.. n​​scanned是巨大的(添加到問題)。間隔不固定,它們是可變的。 – SuitedSloth

回答

1

我想compbound指數應該運行速度更快:

db.blocks.ensureIndex({start:1, end:1}); 

您還可以使用explain看到掃描對象等的數量,並選擇最好的指數。

另外,如果您使用的是mongodb < 2.0,則需要更新到2.0+,因爲索引work faster。 也可以通過limit結果來優化查詢。

+0

感謝您的建議..我實際上已經嘗試了一個複合索引,並且還使用了提示(..)來確保它正在被使用。解釋()證實它是。 .limit(1)將一些查詢減半,但我仍然看到4-5秒的查詢。我使用最新的mongo 2. * – SuitedSloth

+0

我已經從1.6更新到mongo 2.0,但我仍然使用相同的數據路徑..我用新的dbpath啓動mongod,重新導入數據並創建索引(單和化合物)。現在查詢平均10ms :) – SuitedSloth

+0

@JuanD:嗯,奇怪。 docs說,對mongodb 2.0的更新應該不需要重新導入數據和重建索引。在你已經想出來的任何好東西中! –

0

這可能會有所幫助:您如何介紹一些冗餘。如果間隔的長度沒有很大的差異,那麼您可以爲每個記錄引入一個標記字段 - 該標記字段是一個值或表示較大間隔的字符串 - 例如,標記50,000用於標記所有記錄的間隔至少部分在0-50,000範圍內,標記100,000爲50,000-100,000範圍內的所有間隔,以此類推。現在,您可以將標籤作爲主要索引,並將記錄範圍的其中一個端點索引爲次要索引。

大間隔邊緣的記錄會有多個標籤 - 所以我們在說multikeys。在你的查詢中,你當然會計算大的間隔標記並在查詢中使用它。

您大致需要每個標籤的總記錄數SQRT - 只是測試的起點,然後您可以微調大間隔大小。

當然這會使寫入速度變慢。

3

其實我正在處理類似的問題,我的朋友找到了解決這個問題的好方法。

如果沒有重疊的數據,則可以做到這一點:

  1. 使用開始現場排序功能查詢
  2. 驗證與最終場

例如你可以做

var x = 100; 
var results = db.collection.find({start:{$lte:x}}).sort({start:-1}).limit(1) 
if (results!=null) { 
    var result = results[0]; 
    if (result.end > x) { 
    return result; 
    } else { 
    return null; // no range contain x 
    } 
} 

如果您確定總是包含x的範圍,那麼您不必驗證結果。

通過使用這段代碼,你只需要通過開始或結束字段索引,並且您的查詢變得快得多。

---編輯

我做了一些基準,採用綜合指數以100-100,000ms每次查詢,使用一個索引另一方面每次查詢需要1-5ms。

相關問題