假设我有两个集合,A和B,其中之一(集合A)有一个数组,其单元格包含带有少量键的子文档。
我还有一个脚本,它将通过队列(MongoDB外部),在集合B上插入其项,并使用$push将这些项中的任何相关信息推入集合A中数组中的子文档中。随着脚本的运行,集合A中的文档的大小显著增加。
问题似乎是,当一个文档不适合其分配的大小时,MongoDB会在内部移动它,但是它不会释放它以前占用的空间--新的MongoDB文档不会使用这个空间,除非我运行compact或repairDatabase命令。
在我的例子中,脚本似乎很快就会烧坏我的磁盘空间。它在集合B中插入几个项,然后尝试插入集合A中的文档,并且(我猜)重新定位该文档而不重用它的旧位置。也许这并不是每次都会发生,带有填充,但是当这些文档的大小约为10 DB时,这意味着每次发生这种情况,它都会烧掉相当大的DB块,即使实际的数据大小仍然很小。这个过程在几分钟内消耗掉了我的(当然是相当小的) DB。
每次这种情况发生时都需要一个compact或repairDatabase命令,这很笨拙:磁盘上有空间,我希望MongoDB不用显式请求就可以使用它。可以为数组中的子文档单独设置一个集合,这将解决这个问题,而且可能是一个更好的设计,但它将要求我进行我想要避免的联接,这是NoSQL的优点之一。
那么,首先,MongoDB是否真的像我前面描述的那样使用空间?第二,我是不是走错路了?也许我可以设置一个参数来使MongoDB自动重用这个空间;如果有的话,是否应该使用它?第三,还有其他更合适的设计方法吗?
发布于 2013-11-27 18:48:05
Sammaye的建议是正确的,但是我需要做更多的调查来了解这个问题的原因。这是我发现的。
那么,首先,MongoDB是否真的像我前面描述的那样使用空间?
是的,但那不像预期的那样。参见bug 服务器-8078,及其(非明显的)复制,服务器-2958。频繁的$push操作会导致MongoDB对文档进行洗牌,而它们的旧点还没有(现在!)在没有compact或repairDatabase命令的情况下重用。
第二,我是不是走错路了?也许我可以设置一个参数来使MongoDB自动重用这个空间;如果有的话,是否应该使用它?
对于$push的某些用法,usePowerOf2Size选项最初消耗更多内存,但更稳定(参见关于服务器-8078的讨论)。它可能不能很好地处理不断增长的数组,这是个坏主意,因为文档大小是有上限的。
第三,还有其他更合适的设计方法吗?
如果一个数组将有数百个或数千个项,或者它的长度是任意的,但可能很大,那么最好将其单元格移动到不同的集合中,尽管需要额外的数据库调用。
发布于 2013-11-25 23:01:57
你问过的大多数问题你应该已经知道了(Google搜索会带来100多个链接,包括关于这个问题的重要博客文章),但是在这种情况下,这个演示文稿应该回答90%的问题: MongoDB:http://www.mongodb.com/presentations/storage-engine-internals。
至于通过设置等来解决这个问题,在这里不太可能,对于这样的数组来说,2种大小的功率是没有帮助的。因此,要回答:
也许我可以设置一个参数来使MongoDB自动重用这个空间;如果有的话,是否应该使用它?
我会说不。
第三,还有其他更合适的设计方法吗?
对于这种情况,我建议使用单独的集合将每个数组元素存储为独立于父文档的新行。
https://stackoverflow.com/questions/20205008
复制相似问题