MongoDB分页获取数据排序阶段缓存溢出问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongoDB分页获取数据排序阶段缓存溢出问题相关的知识,希望对你有一定的参考价值。
参考技术A查询语法如下:
报错信息如下:
1、 扩大排序内存的限制,例如扩大10倍至320M。如:
2、 给排序字段加索引。如:
3、 在执行一个更大规模排序时,即使已经加了索引依然超过限制,可以使用aggregate()方法的 allowDiskUse 参数设置将数据写到临时文件进行排序。如:
文本搜索中的 MongoDB 溢出排序阶段
【中文标题】文本搜索中的 MongoDB 溢出排序阶段【英文标题】:MongoDB Overflow sort stage on text search 【发布时间】:2014-10-22 17:03:12 【问题描述】:使用MongoDB v2.6,如果从大型结果集中对cursor 进行排序以得到overflow,这种情况并不少见。
cursor = db.collection.find( "key" : "value" )
cursor.sort( "rank" : 1 ) // This can blow up
错误看起来很像:
运行器错误:溢出排序阶段缓冲数据使用量 33598393 字节超过内部限制 33554432 字节
在这种情况下,解决方案是将provide an index 作为排序条件,而不仅仅是键。
db.collection.ensureIndex( "rank" : 1 ) // ascending
这很好用。
我在另一个地方遇到了这个问题,text index。按照text index creation 上的 MongoDB 手册中的说明,我已经做到了:
db.collection.ensureIndex(
"$**": "text" ,
name: "TextIndex"
)
而且,这已经在集合中我的所有 ExtendedJSON 对象的所有字段中创建了一个文本索引。
搜索完美。
cursor = db.collection.find( "$text" : "$search" : "NEEDLE" )
cursor.count() // w00t! records that have NEEDLE in them
但是,尝试执行与以前相同的排序失败,即使排序字段存在索引:
db.collection.ensureIndex( "rank" : 1 )
cursor = db.collection.find( "$text" : "$search" : "NEEDLE" )
cursor.sort( "rank" : 1 ) // This blows up with the same error message
运行器错误:溢出排序阶段缓冲数据使用量 33598393 字节超过内部限制 33554432 字节
这是奇怪的部分。
在光标上迭代 执行排序工作正常,这就是我上面的计数。我什至可以通过光标单步查看 无序 结果,因此文本搜索显然有效。
但是,省略文本搜索会导致排序正常工作;这让我觉得它不是基于数量的,虽然我知道它实际上只是使用排序键的索引。
db.collection.ensureIndex( "rank" : 1 )
cursor = db.collection.find( ) // Get absolutely everything
cursor.sort( "rank" : 1 ) // Well, sort now works again... hmm....
正如我必须通过提供一个索引来“帮助”Mongo,这样它就可以在不将所有记录放入内存的情况下进行排序,如何为文本索引实现这一点?
不幸的是,我无法获得explain plan,因为它也会产生相同的错误。如果我对.find() sans .sort() 的结果执行此操作,它会显示明显的结果——对数据进行全面扫描,没有IndexBounds
字段。
附录:我尝试对文本索引的不是一个字段,而是所有字段——因此是"$**"
。作为实验,我在所有字段上手动执行了.ensureIndex(...)
,希望这对排序有所帮助。但请记住,我并不是要对文本字段进行排序——只是将其作为一种机制来获取与搜索条件匹配的 JSON 对象集合。一旦我拥有了该集合,并且确实获得了该集合,我将尝试按 rank
字段对其进行排序,该字段已经有一个索引并且可以在其他场景中使用。
【问题讨论】:
在上面的示例中,我并没有尝试获取文本搜索的排名,而只是使用文本搜索来选择记录(获取子集);记录本身具有与之关联的独立排名字段,因此目标是按该值对返回的子集进行排序——因此是上面的代码。 虽然两者都是索引,但文本索引和“普通”索引在它们的实际功能(以及底层数据结构)方面完全不同。文本索引无法像“普通”索引那样帮助您对文本字段的值进行排序。在文本字段上创建一个“正常”索引并使用它进行排序。但是,在您使用文本搜索的相同字段上进行排序似乎有点时髦,除非它们只是标题或其他东西。 @wdberkeley:(请参阅上面的附录。)它不是单个文本字段[在“文本字段”上方],而是所有字段“$**”[如文档所述]。虽然全文搜索正在工作,但它是返回的集合,我无法通过我预先存在的具有索引的“排名”字段进行排序,尽管我可以通过它对其他查询进行排序就好了。我希望我只是误解了你的建议,所以我有一条路可以尝试。你能描述一下'在文本字段上创建一个“正常”索引并使用它来排序'的意思吗?我有多个要在其中搜索的字段和一个要排序的字段。非常感谢。 好的。我明白发生了什么。文本索引阻止您使用排名索引进行排序。然后 MongoDB 尝试按等级对内存进行排序,但这样做会达到内存限制。我认为除了自己对其进行排序或将结果数限制为可排序数之外,没有其他方法可以解决此问题。如果我想到其他任何事情,我会告诉你的。 【参考方案1】:也许这个link 会帮助你。
总结一下:你不应该在你的程序中间调用 ensureIndex,而是让 Mongoose 为你调用它。只需将标志index: true
在您的架构中添加到您要用于排序的字段中。在您的情况下,将其添加到排名和命名应该没问题。至少这在我的项目中对我有用。
例子:
var schema = mongoose.Schema(
...
normalText : String,
rank : type: Number, index: true,
name : type: String, index: true
);
【讨论】:
感谢您的提示,斯特凡!作为一个仅供参考,只是为了让您放心,上面的示例是针对 mongo> shell 的,用于说明问题。我同意,不要将 ensureIndex 放在程序中。【参考方案2】:希望这会有所帮助。 尝试添加这样的代码。 这是为了排序。 $cursor = $cursor.sort( "rank" : 1 )); 但是你需要对 $text 进行排序, 试试这个, $cursor = $cursor->sort( "text" : 1 );
谢谢。
【讨论】:
以上是关于MongoDB分页获取数据排序阶段缓存溢出问题的主要内容,如果未能解决你的问题,请参考以下文章