确实使用$ sort进行排序,或者阻止在mongodb中使用索引?

问题描述:

它看起来像使用$或与排序做一个完整的表扫描,并避免我的标题和关键字索引我怎么能得到它使用我的两个索引时使用$或查询?

这个查询使用标题和关键字索引

db.tasks.find({$or: [{keywords: /^japan/}, {title:/^japan/}]}) 

这个执行全表扫描,并使用我的索引total_-1

db.tasks.find({$or: [{keywords: /^japan/}, {title:/^japan/}]}).sort({total:-1}) 

而针对关键字或标题查询带有几分做分别使用关键字或标题上的索引。

db.tasks.find({title:/^japan/}).sort({total:-1}) 
db.tasks.find({keywords:/^japan/}).sort({total:-1}) 

Mongo中的排序和索引是一个复杂的话题。如果你有太多的项目,Mongo也有一个特殊的错误,它会阻止你在没有索引的情况下进行排序。所以你最好问索引,因为一个未索引的类最终会失败。

有一个bug in JIRA似乎涵盖您的问题,但有一些额外的细节要考虑。

要注意的第一件事情是你最后的疑问:

db.tasks.find({title:/^japan/}).sort({total:-1}) 
db.tasks.find({keywords:/^japan/}).sort({total:-1}) 

因为你是唯一的索引上title不是title/total这些查询最终将失败。这里有一个脚本来演示这个问题。

> db.foo.ensureIndex({title:1}) 
> for(var i = 0; i < 100; i++) { db.foo.insert({title: 'japan', total: i}); } 
> db.foo.count() 
100 
> db.foo.find({title: 'japan'}).sort({total:-1}).explain() 
... uses BTreeCursor title_1 
> // Now try with one million items 
> for(var i = 0; i < 1000000; i++) { db.foo.insert({title: 'japan', total: i}); } 
> db.foo.find({title: 'japan'}).sort({total:-1}).explain() 
Sat Mar 31 05:57:41 uncaught exception: error: { 
     "$err" : "too much data for sort() with no index. add an index or specify a smaller limit", 
     "code" : 10128 
} 

所以,如果你打算查询&排序上titletotal,那么你就需要在这两个指标,按照这个顺序:

> db.foo.ensureIndex({title:1,total:1}) 
> db.foo.find({title: 'japan'}).sort({total:-1}).explain() 
{ 
     "cursor" : "BtreeCursor title_1_total_1 reverse", 
... 

我上面列出的JIRA的bug是有点像以下:

> db.foo.find({$or: [title:/^japan/, title:/^korea/]}).sort({total:-1}) 

此致略有不同,但会遇到同样的问题。即使您在title/totalkeyword/total上都有索引,MongoDB也无法以最佳方式使用索引。

+0

如果您有{total:-1,title:1}的索引并按{total:-1,title:1}排序,那么至少是否使索引扫描更有效? – drogon 2013-02-25 23:08:06

+0

@drogon你在过滤什么?那里有一个'find()'子句吗? JIRA错误是非常具体的使用'$或'子句进行排序。 – 2013-02-26 23:13:12