2016-06-07 96 views
3

從mongodb集合中選擇隨機文檔的方法很多(如in this answer所述)。評論指出,在mongodb版本> = 3.2的情況下,在聚合框架中使用$sample是首選。然而,在一個有許多小文件的收藏中,這似乎非常緩慢。

下面的代碼使用mongoengine來模擬這個問題,並把它比作「跳過隨機」方法:

import timeit 
from random import randint 

import mongoengine as mdb 

mdb.connect("test-agg") 


class ACollection(mdb.Document): 
    name = mdb.StringField(unique=True) 

    meta = {'indexes': ['name']} 


ACollection.drop_collection() 

ACollection.objects.insert([ACollection(name="Document {}".format(n)) for n in range(50000)]) 


def agg(): 
    doc = list(ACollection.objects.aggregate({"$sample": {'size': 1}}))[0] 
    print(doc['name']) 

def skip_random(): 
    n = ACollection.objects.count() 
    doc = ACollection.objects.skip(randint(1, n)).limit(1)[0] 
    print(doc['name']) 


if __name__ == '__main__': 
    print("agg took {:2.2f}s".format(timeit.timeit(agg, number=1))) 
    print("skip_random took {:2.2f}s".format(timeit.timeit(skip_random, number=1))) 

結果是:

Document 44551 
agg took 21.89s 
Document 25800 
skip_random took 0.01s 

只要我有性能問題mongodb在過去我的答案一直是使用匯總框架,所以我很驚訝$sample是如此之慢。

我在這裏錯過了什麼嗎?這個例子是什麼導致聚合需要這麼長時間?

+1

你在運行什麼MongoDB版本?我發現'$ sample'在3.2.5中很慢,但在3.2.7基本上是瞬時的。 – JohnnyHK

+0

啊,3.2.0 - 那就是它。是的,[this](https://jira.mongodb.org/browse/SERVER-21887?jql=text%20~%20%22%24sample%22)表明這是一個已知的錯誤。 –

+0

沒錯,但是我不確定爲什麼3.2.5版本中爲什麼它仍然很慢,因爲它在3.2.3中被標記爲固定。 – JohnnyHK

回答