我有一个大约30K项目的集合,所有项目都有一个名为Program的元素。 “程序”是复合索引的第一部分,因此查找具有特定程序值的项目非常快。运行范围查询也很快,例如:
db.MyCollection.find(
{ $and: [ { Program: { "$gte" : "K", "$lt" : "L" } },
{ Program: { "$gte" : "X", "$lt" : "Y" } } ] }).count();
上面的查询没有返回任何结果,因为我正在查询两个非重叠范围(K-L)和(X-Y)的重叠。左范围(K-L)包含约7K项目。
但是,如果我用“where”表达式替换第二个“and”子句,则查询执行需要很长时间:
db.MyCollection.find(
{ $and: [ { Program: { "$gte" : "K", "$lt" : "L" } }, { "$where" : "this.Program == \"Z\"" } ] }).count();
如您所见,上面的查询也应该返回一个空结果集(范围K-L与Program ==“Z”组合)。我知道“where”的性能很慢,但是Mongo不应该首先通过评估left子句来减少潜在的结果集(这将导致大约7K项),然后才应用“where”检查?如果确实如此,那么在我的机器上处理几千件物品时不应该花费几秒而不是几分钟,而Mongo服务在执行此操作时会消耗大约3GB RAM吗?对于相对较小的收藏来说看起来太重了。
答案 0 :(得分:3)
你可以做一些事情 -
使用explain()
查看您的查询发生了什么。 explain()
被描述为here。使用$ explain运算符返回描述用于返回查询的进程和索引的文档。例如 -
db.collection.find(查询).explain()
如果这不能返回足够的信息,您可以查看Database Profiler。但是,请记住,这不是免费的,并且本身会增加负载。在此页面中,您还可以找到有关优化查询效果的基本notes。
但是,在您的情况下,这一切都归结为$ where运算符:
$ where评估JavaScript并且无法利用索引。因此,当您使用标准MongoDB运算符(例如,$ gt,$ in)表达查询时,查询性能会提高。
通常,只有当您无法使用其他运算符表达查询时,才应使用$ where。如果必须使用$ where,请尝试包含至少一个其他标准查询运算符以过滤结果集。单独使用$ where需要进行表扫描。 $ where,与Map Reduce一样,限制了您的concurrency。
作为一个FYI:有关explain()
的输出的几点注意事项:
ntoreturn
客户端请求从查询返回的对象数。例如,findOne()
,将ntoreturn设置为limit()
设置适当的限制。零表示没有限制。query
查询规范的详细信息。nscanned
执行操作时扫描的对象数。reslen
查询结果长度,以字节为单位。nreturned
查询返回的对象数。