【问题标题】:Ridiculously slow mongoDB query on small collection in simple but big database在简单但大数据库中对小集合的 mongoDB 查询速度非常慢
【发布时间】:2013-01-01 09:10:57
【问题描述】:

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

> show collections
Aggregates <-- count: 92
Users <-- count: 68222
Pages <-- count: 1728288847, about 1.1TB
system.indexes

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

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

非常简单。但是,让我们尝试通过将所有 92 天 daily page loads 加在一起来获得总页面加载:

>>> 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

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
}

每天这些微小的数字总共有 438 兆字节?每个大约是 280 字节,所以它们的最大总数应该是 25~30kb。所以存储量很大,查询超级慢。它有可能在磁盘上碎片化吗?在将文档插入完整的Pages 集合后,我创建了聚合。

有人对这种疯狂有任何见解吗? :O


编辑:解决了 Jared 更具体的 find() 查询。 Sammaye 提供的以下视频也提供了一些非常有趣的存储见解。


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

【问题讨论】:

  • 您的服务器上有多少可用磁盘空间? Mongo 在分配磁盘空间方面是非常激进的。阅读此docs.mongodb.org/manual/faq/storage/#faq-disk-size 很快,Mongo 将为每个新数据库创建一个 2GB 的文件。此外,您可能打开了日记功能,这也会占用大量空间。
  • 我还有 508GB 的​​磁盘空间,处理器以 99% 的空闲状态运行,还有 32gb 的内存,基本上都没有使用 :(
  • 那时我不知道。你是对的,它是一个小集合,应该运行得很快。我不知道 Python,但我的最后一个猜测是你正在调用的调用运行 Aggregates.find() 不止一次,这会增加运行时间。
  • 嗯 mongo 说平均对象大小实际上是 4mb,而不是您认为的 280 字节 (avgObjSize),这将产生 300 多个兆我会说其余的可能是未来范围和碎片的预分配.至于运行速度慢,你能告诉我们你查询的那个时期的 iostat -x 吗?
  • 这真的与 MongoDB 的内部结构以及它如何处理命名空间有关,我没有关于它的文档页面,但基本上这个演示文稿可能在这里有所帮助:10gen.com/presentations/storage-engine-internals 基本上删除一个集合只是把所有该空间释放空间,在删除记录时更容易重用,然后放入删除桶列表,如果您更改记录的大小可能意味着其中大部分不可再生

标签: mongodb optimization query-optimization pymongo database


【解决方案1】:

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

你试过compacting吗?

db.runCommand({compact: 'Aggregates'})

repairing?

db.repairDatabase()

如果这不起作用,请尝试仅拉回总和所需的那些字段,而不是拉整个文档。可能这些文档实际上是 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

【讨论】:

  • 好的,所以我运行了压缩和相同的时间。现在尝试修复数据库
  • > db.repairDatabase() { "errmsg" : "无法修复大小为 1262054539264 (bytes) 的数据库 c,因为可用磁盘空间为:545048477696 (bytes)", "ok" : 0 } >
  • compact 之后,集合稍微小了一点
  • 天哪!新的查询大大加快了速度!一秒钟,将在我的整个集群中尝试一下
  • 好的,所以现在我可以快速查询(向 Jared,查询之神鞠躬)但是是的,根本没有那么多数据,每个文档实际上是 280 字节。循环遍历每个文档并为每个文档获取 sys.getsizeof() 只需 280。哼哼。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-11
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多