当前位置: 首页 > 知识库问答 >
问题:

MongoDB对超过500万条记录的查询性能

巢德华
2023-03-14
db.events.ensureIndex({somefield: 1, timestamp:-1})

我已经确保使用explain查询确实使用了我创建的索引,但性能仍然不够好。

我在想,现在是不是该去sharding了..但是我们很快就会开始每天有大约100万张新唱片在这个收藏中…所以我不确定它是否能很好地扩展..

编辑:查询示例:

> db.audit.find({'userAgent.deviceType': 'MOBILE', 'user.userName': {$in: ['nickey@acme.com']}}).sort({timestamp: -1}).limit(25).explain()
{
        "cursor" : "BtreeCursor user.userName_1_timestamp_-1",
        "isMultiKey" : false,
        "n" : 0,
        "nscannedObjects" : 30060,
        "nscanned" : 30060,
        "nscannedObjectsAllPlans" : 120241,
        "nscannedAllPlans" : 120241,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 1,
        "nChunkSkips" : 0,
        "millis" : 26495,
        "indexBounds" : {
                "user.userName" : [
                        [
                                "nickey@acme.com",
                                "nickey@acme.com"
                        ]
                ],
                "timestamp" : [
                        [
                                {
                                        "$maxElement" : 1
                                },
                                {
                                        "$minElement" : 1
                                }
                        ]
                ]
        },
        "server" : "yarin:27017"
}

请注意,deviceType在我的集合中只有2个值。

共有1个答案

彭烨烁
2023-03-14

这是大海捞针。对于那些执行不佳的查询,我们需要explain()的一些输出。不幸的是,即使这样也只能解决特定查询的问题,所以这里有一个如何解决这个问题的策略:

  1. 确保不是因为RAM不足和过度分页
  2. 启用DB探查器(使用DB.setprofilinglevel(1,timeout),其中timeout是查询或命令所用的毫秒数的阈值,任何较慢的都将被记录)
  3. 检查db.system.profile中的慢速查询,并使用explain()
  4. 手动运行这些查询
  5. 尝试识别explain()输出中的慢操作,如scanandorder或大型nscanned等。
  6. 查询选择性的原因,以及是否可以使用索引改进查询。如果没有,请考虑禁用最终用户的筛选器设置,或者给他一个警告对话框,说明操作可能很慢。

一个关键问题是,您显然允许您的用户随意组合过滤器。如果没有索引相交,这将大大增加所需索引的数量。

此外,盲目地向每个可能的查询抛出索引是非常糟糕的策略。构造查询结构并确保索引字段具有足够的选择性是很重要的。

假设您有一个针对所有具有状态“active”和其他条件的用户的查询。但是在500万用户中,300万活跃,200万不活跃,所以超过500万的条目只有两个不同的值。这样的索引通常没有帮助。最好先搜索其他条件,然后扫描结果。平均而言,当返回100个文档时,您必须扫描167个文档,这不会太严重地损害性能。但事情没那么简单。如果主要标准是用户的joined_at日期,并且用户随时间停止使用的可能性很高,那么在找到100个匹配项之前,您可能不得不扫描数千个文档。

因此,优化在很大程度上取决于数据(不仅是它的结构,还有数据本身)、内部相关性和查询模式。

如果所有其他方法都失败了,并且如果您确实需要在筛选器中具有如此大的灵活性,那么考虑一个支持索引交叉的单独搜索DB,从那里获取mongo ID,然后使用$in从mongo获取结果可能是值得的。但这也充满了自身的危险。

--编辑--

你发布的解释是一个关于扫描低选择性场的问题的漂亮例子。显然,“nickey@acme.com”有很多文档。现在,查找这些文档并按时间戳降序排序非常快,因为它得到了高选择性索引的支持。不幸的是,由于只有两种设备类型,mongo需要扫描30060个文档才能找到与“移动”匹配的第一种。

a) ensureIndex({'username': 1, 'userAgent.deviceType' : 1, 'timestamp' :-1})

b) ensureIndex({'userAgent.deviceType' : 1, 'username' : 1, 'timestamp' :-1})

不幸的是,这意味着像find({“username”:“foo”}).sort({“timestamp”:-1});这样的查询不能再使用相同的索引,因此,如上所述,索引的数量将迅速增长。

恐怕目前使用mongodb还没有很好的解决方案。

 类似资料:
  • 我试图在mongodb日志文件中只记录慢速查询(执行时间超过10秒)。 我在运行蒙戈作为 并将分析设置为 但是当跟踪日志文件时,它会打印所有的查询。我可以看到很多查询,它的运行时间为0ms。我还需要添加什么来只获得慢速查询吗?

  • 我在mongodb文档中存储图书元数据,如名称、作者、价格、出版商等。我有大约1000万份这些文件,它们都在一个收藏中。平均文档大小为1.9KB。现在我有了关于、和的索引。事实上,我有两个价格指数,一个是升序,一个是降序。我的mongodb版本是2.2.0,我正在使用php驱动程序查询Mongo。驱动程序的版本是1.12。但是当我对price进行范围查询时,我会得到一个。在我的查询中,我试图找到的

  • 我们不敢相信我们在问这个问题<我们如何查询SQLite数据库中的一条记录 假设我们想要id,但只知道表中的名称 这是调用DB的代码 这里是DB乐趣getOneName 这个数据库有一个模型,应用程序有一个适配器 } 我们想输入名称并检索id,但我们甚至无法检索名称<我们已经在Java中多次这样做了,但Kotlin没有成功

  • 我正在开发spring-mvc应用程序。 我需要处理超过10万条数据记录。我不能让它依赖于数据库,所以我必须用java实现所有逻辑。 目前,我正在创建多个线程,并将1000条记录分配给每个要处理的线程。 我正在使用org。springframework。行程安排。同时发生的ThreadPoolTaskExecutor(线程池任务执行器)。 列表项 问题: 建议使用的线程数 我应该在线程之间平均分配

  • 我有一个“Customer”表,它有将近120万条记录,其中一列是ntext类型的“customer_records ”,它包含xml数据。我需要在该列的所有现有记录中替换一个url值。我尝试了下面的替换查询,但是执行该查询需要大约20分钟的时间。 在更新期间,CPU 消耗被利用到最大,这引起了问题。在 120 万条记录中,实际更新的记录中有 60 万条记录,但查询需要读取每条记录以查找和替换 U