1

我收集了大约 30K 个项目,所有这些项目都有一个名为 Program 的元素。“程序”是复合索引的第一部分,因此查找具有特定程序值的项目非常快。运行范围查询也很快,例如:

db.MyCollection.find(
{ $and: [ { Program: { "$gte" : "K", "$lt" : "L" } }, 
{ Program: { "$gte" : "X", "$lt" : "Y" } } ] }).count();

上面的查询没有返回任何结果,因为我正在查询两个非重叠范​​围(KL)和(XY)的重叠)。左侧范围 (KL) 包含大约 7K 项。

但是,如果我用“where”表达式替换第二个“and”子句,查询执行需要很长时间:

db.MyCollection.find(
{ $and: [ { Program: { "$gte" : "K", "$lt" : "L" } }, { "$where" : "this.Program == \"Z\"" } ] }).count();

如您所见,上面的查询也应该返回一个空结果集(范围 KL 与 Program=="Z" 结合)。我知道“where”的性能很慢,但是 Mongo 不应该首先通过评估 left 子句(这将导致大约 7K 项)来减少潜在的结果集,然后才应用“where”检查?如果是这样,处理几千个项目是否应该像在我的机器上那样花费几秒钟而不是几分钟,而 Mongo 服务在执行此操作时消耗大约 3GB RAM?相对较小的收藏看起来太重了。

4

1 回答 1

3

你可以做几件事——

  1. 用于explain()查看您的查询发生了什么。explain()描述here。使用 $explain 运算符返回描述用于返回查询的过程和索引的文档。例如 -

    db.collection.find(查询).explain()

  2. 如果这没有返回足够的信息,您可以查看使用Database Profiler。但是,请记住,这不是免费的,它本身会增加负载。在此页面中,您还可以找到一些关于优化查询性能的基本说明。

  3. 但是,就您而言,这一切都归结为 $where 运算符:

    $where 评估 JavaScript 并且不能利用索引。因此,当您使用标准 MongoDB 运算符(例如,$gt、$in)表达查询时,查询性能会提高。

    通常,只有在无法使用其他运算符表达查询时才应使用 $where。如果您必须使用 $where,请尝试至少包含一个其他标准查询运算符来过滤结果集。单独使用 $where 需要进行表扫描。$where 和 Map Reduce 一样,会限制你的并发

仅供参考:关于以下输出的几点注意事项explain()

  • ntoreturn客户端请求从查询中返回的对象数。例如findOne(),设置 ntoreturn 以limit()设置适当的限制。零表示没有限制。
  • query查询规范的详细信息。
  • nscanned执行操作时扫描的对象数。
  • reslen查询结果长度(以字节为单位)。
  • nreturned从查询返回的对象数。
于 2012-07-26T14:21:18.560 回答