MongoDB OR条件索引化

3

我有一个OR查询,目前正在用于半大型更新。我的集合分为两个数据集; 1个主存储库和1个主存储库的子集。这只是为了在少量数据的快速搜索。

然而,我发现我创建的查询拉取子集中的内容时超时了。当查看解释时,似乎实际上发生了两个查询。

PRIMARY> var date = new Date(2012,05,01);
PRIMARY> db.col.find(
  {"$or":[
      {"date":{"$gt":date}},
      {"keywords":{"$in":["Help","Support"]}}
   ]}).explain();

这将产生以下结果:
{
"clauses" : [
    {
        "cursor" : "BtreeCursor ldate_-1",
        "nscanned" : 1493872,
        "nscannedObjects" : 1493872,
        "n" : 1493872,
        "millis" : 1035194,
        "nYields" : 3396,
        "nChunkSkips" : 0,
        "isMultiKey" : false,
        "indexOnly" : false,
        "indexBounds" : {
            "ldate" : [
                [
                    ISODate("292278995-01--2147483647T07:12:56.808Z"),
                    ISODate("2012-06-01T07:00:00Z")
                ]
            ]
        }
    },
    {
        "cursor" : "BtreeCursor keywords_1 multi",
        "nscanned" : 88526,
        "nscannedObjects" : 88526,
        "n" : 2515,
        "millis" : 1071902,
        "nYields" : 56,
        "nChunkSkips" : 0,
        "isMultiKey" : false,
        "indexOnly" : false,
        "indexBounds" : {
            "keywords" : [
                [
                    "Help",
                    "Help"
                ],
                [
                    "Support",
                    "Support"
                ]
            ]
        }
    }
],
 "nscanned" : 1582398,
 "nscannedObjects" : 1582398,
 "n" : 1496387,
 "millis" : 1071902
}

有没有什么我可以更好地索引以使其更快?似乎太慢了...

提前感谢!


你的索引是什么?只是一个日期字段吗? - RameshVel
我尝试过在关键字和日期上创建单独的索引;并尝试将它们作为跨两个索引的复合索引创建。 - Petrogad
@Sammaye 我正在尝试获取所有符合条件的记录,并将它们移动到另一个集合中,只保留实际字段的子集,从而创建一个可搜索的数据集。 - Petrogad
你是在尝试为另一个集合进行聚合,对吗?这是客户端还是基于MR的?如果是客户端,使用的是哪种语言(可能会因为可能存在的驱动程序错误而有所不同)? - Sammaye
@Sammaye 通过 CLI 接口在批处理 cron 作业中的客户端 (php) 中进行。 - Petrogad
显示剩余5条评论
2个回答

1

一个 $or 查询 将会逐个计算每个子句,并将结果合并以去除重复项。所以,如果您想优化查询,应该首先尝试逐个 explain() 每个子句。

看起来问题的一部分是在您正在写入集合的同时检索大量文档,如高 nYields (3396) 所示。在查询运行时,值得查看 mongostat 输出以考虑其他因素,例如页面故障,锁定百分比和读写队列。

如果要针对大量文档和非常活跃的集合更新使此查询更快,可以考虑两种最佳实践方法:

1)预聚合

本质上,这是在插入/更新文档时更新聚合统计数据,以便您可以进行快速实时查询。 MongoDB手册更详细地描述了此用例:预聚合报告

2)增量Map / Reduce

可以使用增量Map / Reduce方法来计算连续批次的聚合统计数据(例如,从每小时或每日的cron作业)。 采用这种方法,您使用reduce输出选项执行Map / Reduce,将结果保存到新集合中,并包括一个query过滤器,仅选择自上次运行此Map / Reduce作业以来已创建/更新的文档。


0

刚刚检查了一下,但似乎“或”条件仍然会命中两个索引。我想这会使它变慢,因为它必须两次查看完全相同的索引,只使用了其中一半的信息。 - Petrogad
1
$or可以使用两个索引计划,并且它是Mongo查询的一种特殊情况。从根本上讲,它源于$or在Mongo中的实现方式。 - Sammaye
复合索引并不会有所帮助;正如Sammaye所提到的$or使用多个索引(每个子句一个)并将结果组合以去除重复项。 - Stennie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接