在简单但大型数据库中对小集合进行mongoDB查询的速度非常慢

Lit*_*les 7 database optimization query-optimization mongodb pymongo

所以我在mongoDB中有一个超级简单的数据库,有一些集合:

> show collections
Aggregates <-- count: 92
Users <-- count: 68222
Pages <-- count: 1728288847, about 1.1TB
system.indexes
Run Code Online (Sandbox Code Playgroud)

Aggregates集合是集合的Pages集合,每个文档如下所示:

> db.Aggregates.findOne()
{
        "_id" : ObjectId("50f237126ba71610eab3aaa5"),
        "daily_total_pages" : 16929799,
        "day" : 21,
        "month" : 9,
        "year" : 2011
}
Run Code Online (Sandbox Code Playgroud)

非常简单.但是,让我们daily page loads一起添加所有92天来尝试获取总页面加载:

>>> def get_total():
...     start = datetime.now()
...     print sum([x['daily_total_pages'] for x in c.Aggregates.find()])
...     end = datetime.now()
...     print (end-start).seconds
...
>>> get_total()
1728288847
43
Run Code Online (Sandbox Code Playgroud)

43秒?!??!??!?!

那92个总结果很小!我不妨将它们存储在一个文本文件中,这很疯狂.

还是他们很小?根据mongo,它们在磁盘上有多大?

> db.Aggregates.stats()
{
        "ns" : "c.AggregateResults",
        "count" : 92,
        "size" : 460250104,
        "avgObjSize" : 5002718.521739131,
        "storageSize" : 729464832,
        "numExtents" : 7,
        "nindexes" : 2,
        "lastExtentSize" : 355647488,
        "paddingFactor" : 1.0690000000000066,
        "systemFlags" : 1,
        "userFlags" : 0,
        "totalIndexSize" : 16352,
        "indexSizes" : {
                "_id_" : 8176,
                "date_1" : 8176
        },
        "ok" : 1
}
Run Code Online (Sandbox Code Playgroud)

这些微小的每日数字共计438兆字节?每个大约280字节,因此它们最多应为25~30kb.因此存储量很大,查询速度非常慢.是否有可能在磁盘上碎片化?我在将文档插入完整Pages集合后创建了聚合.

任何人都对这种疯狂有任何见解?:o


编辑:由Jared更具体的find()查询解决.Sammaye提供的视频也提供了一些非常有趣的存储洞察.


编辑2:所以我发现使用sys.getsizeof()是一种非常不可靠的方法来查找文档的大小,因为它不会递归任何树.所以实际上我的文档非常大,最好的办法是使用find({},{'daily_page_loads'})作为更具体的查询!

jar*_*red 9

avgObjSize与280字节的估计不符.它说你的对象平均大约5MB,storageSize接近1GB.如果内存受限,运行需要访问所有1GB文件的查询会导致大量页面错误.

你试过压缩吗?

db.runCommand({compact: 'Aggregates'})
Run Code Online (Sandbox Code Playgroud)

修理

db.repairDatabase()
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,请尝试拉回总和所需的那些字段,而不是拉动整个文档.可能这些文档实际上是5MB,并且花费时间来通过网络提取数据.

def get_total():
    start = datetime.now()
    print sum([x['daily_total_pages'] for x in c.Aggregates.find({}, {"daily_total_pages": 1})])
    end = datetime.now()
    print (end-start).seconds
Run Code Online (Sandbox Code Playgroud)