2011-02-09 29 views
4

我正在使用MongoDB作爲臨時日誌存儲。該系列每小時收到約400,000新的行。每行包含一個UNIX時間戳和一個JSON字符串。用於日誌數據的MongoDB集合:索引與否?

定期我想將集合的內容複製到S3上的文件中,爲包含〜400,000行的每個小時創建一個文件(例如today_10_11.log包含在上午10點到11點之間收到的所有行)。我需要在集合正在接收插入時做這個副本。

我的問題:在400,000小時插入的時間戳列上有一個索引對性能的影響是多少時間查詢一小時的行數。

有問題的應用程序使用Heroku編寫的Ruby編寫,並使用MongoHQ插件。

回答

4

默認情況下,Mongo會索引_id字段,並且ObjectId已經以時間戳開始,所以基本上,Mongo已經通過插入時間爲您創建索引。因此,如果您使用的是Mongo默認值,則無需索引第二個時間戳字段(或者甚至添加一個)。

獲取對象ID的創建時間紅寶石:

ruby-1.9.2-p136 :001 > id = BSON::ObjectId.new 
=> BSON::ObjectId('4d5205ed0de0696c7b000001') 
ruby-1.9.2-p136 :002 > id.generation_time 
=> 2011-02-09 03:11:41 UTC 

要生成的對象ID在給定時間:

ruby-1.9.2-p136 :003 > past_id = BSON::ObjectId.from_time(1.week.ago) 
=> BSON::ObjectId('4d48cb970000000000000000') 

因此,舉例來說,如果你想加載在過去一週插入的所有文檔,您只需搜索大於past_id且小於id的_ids。因此,通過Ruby驅動程序:

collection.find({:_id => {:$gt => past_id, :$lt => id}}).to_a 
=> #... a big array of hashes. 

你可以,當然,還添加了獨立字段的時間戳,並建立索引,但沒有點時服用蒙戈的已經爲你做了必要的工作,性能損失與其默認的_id字段。

More information on object ids.

+0

這是關於BSON ID中的日期的好建議。我必須有一個時間戳記跟蹤器,因爲我還導入了大量插入日期不是事件日期的舊日誌。但我認爲,在這裏的應用程序,你的解決方案可能會很好。 – 2011-02-09 15:07:21

1

當然,在每次寫入時,您都需要更新索引數據。如果你打算對數據進行大量查詢,你肯定會需要一個索引。

考慮將時間戳存儲在_id字段而不是MongoDB ObjectId中。只要你存儲獨特的時間戳,你就可以在這裏。 _id不一定是ObjectID,但在_id上有一個自動索引。這可能是你最好的選擇,因爲你不會增加額外的索引負擔。

1

我只是使用一個封頂的集合,未索引,空間用於說600k行,以允許搪塑。每小時一次,將集合轉儲到文本文件中,然後使用grep過濾掉不符合目標日期的行。這不會讓你充分利用數據庫的優點,但這意味着你不必擔心收集索引,刷新或任何廢話。它的性能關鍵點是保持插入的可用集合,所以如果你可以在數據庫的上下文之外執行「硬」位(按日期過濾),則不應該有任何明顯的性能影響。對於grep,400-600k行文本是微不足道的,可能不會超過一秒或兩秒。

如果您不介意每個日誌中有一點瑕疵,那麼您可以轉儲並gzip該集合。每次轉儲都會得到一些較舊的數據,但除非在轉儲之間插入超過600k行,否則應該有一組連續的600k行日誌快照。

4

我有一個像你這樣的應用程序,目前它有1.5億條日誌記錄。在每小時40萬的時候,這個數據庫會快速增長。 400k插入一小時索引的時間戳將比做一個無索引查詢更有價值。我在使用索引時間戳的一小時內插入數千萬條記錄時沒有問題,但是如果我在時間戳上執行未索引的查詢,則需要幾分鐘的時間處理4個服務器碎片(cpu bound)。索引查詢立即出現。所以絕對索引它,索引編寫的開銷並不高,一個小時的400k記錄對於mongo來說並不算多。

你必須注意的一件事是內存大小。每小時40萬條記錄,你每天要做1000萬條記錄。這將消耗每天大約350MB的內存,以將該索引保存在內存中。所以如果這一段時間你的索引可能比內存快得多。

此外,如果您使用remove在一段時間後截斷記錄,我發現刪除會在磁盤上創建大量的IO,並且它是磁盤綁定的。

+0

邁克爾,謝謝你的建議。我正在刪除記錄,所以我會密切關注IO性能。 – 2011-02-09 22:17:13