【问题标题】:MongoDB query taking too much time to retrieve dataMongoDB查询花费太多时间来检索数据
【发布时间】:2017-10-03 07:03:51
【问题描述】:

我有一个包含 300 万个文档和以下索引的集合:

{ ts : 1 } , {u_id: 1}

请注意,这是两个独立的升序索引,而不是复合索引。

当我运行这个查询时:

db.collection.find({u_id: 'user'}).sort({ts : -1}).skip(0).limit(1)

需要 +100 毫秒。我有以下日志:

2017-04-15T06:42:01.147+0000 I COMMAND [conn783] 查询
db.collection 查询:{ orderby:{ ts:-1 },$query:{
u_id: "user-ki-id } } planSummary: IXSCAN { u_id:
1 }, IXSCAN { u_id: 1 } ntoreturn:1 ntoskip:0 keysExamined:10795
docsExamined:10795 hasSortStage:1 cursorExhausted:1 keyUpdates:0
writeConflicts:0 numYields:86 nreturned:1 reslen:771 locks:{ Global: {
获取计数:{ r:174 } },数据库:{获取计数:{ r:87 } },
集合:{ acquireCount: { r: 87 } } } 246ms

关于这个问题的几个值得注意的点:

  • MongoDB 上没有其他负载,即没有其他需要 +100 毫秒的查询
  • 这种情况每分钟都在发生;我想我每分钟都在存储数据,所以这种情况正在发生
  • 查询流程是先运行读取查询(如上),然后下一个查询是批量插入。此流程每分钟重复一次。

所以我的问题是:

  • 为什么会这样?我的索引是否存在设计缺陷?
  • 是否值得将索引更改为降序,例如 {ts: -1}?这些索引之间的实际区别是什么?
  • 根据 MongoDB 文档,当您按顺序进行排序时,结果将从磁盘而不是“内存”中选择。这是否解释了为什么需要 +100 毫秒?
  • 谁能详细解释一下分析日志?
  • 这是 MongoDB 的期望行为吗?

当我对该集合运行范围搜索时,也会发生同样的事情;这需要 3-5 秒。

编辑: 我只添加了 {u_id: 1, ts: -1} 索引。删除所有其他索引(_id 除外)。仍然是第一次查询执行需要 +100 毫秒。这不应该发生。
查询:

db.getCollection('locations') .find({u_id: "USR-WOWU"}) .sort({ts: -1}) .explain(true)

输出::

/* 1 */ { “查询计划者”:{ “计划者版本”:1, “命名空间”:“db_name.collection_name”, “indexFilterSet”:假, “解析查询”:{ “用户身份” : { "$eq" : "USR-WOWU" } }, “获胜计划”:{ “阶段”:“获取”, “输入阶段”:{ “阶段”:“IXSCAN”, “键模式”:{ “u_id”:1.0, “ts”:-1.0 }, “indexName”:“u_id_1_ts_-1”, “isMultiKey”:假, “isUnique”:假, “isSparse”:假, “isPartial”:假, “索引版本”:1, “方向”:“前进”, “索引边界”:{ “u_id”:[ "[\"USR-WOWU\",\"USR-WOWU\"]" ], “ts”:[ “[最大键,最小键]” ] } } }, “拒绝计划”:[] }, “执行统计”:{ “执行成功”:真, “nReturned”:164, “执行时间米利斯”:119, “totalKeysExamined”:164, “totalDocsExamined”:164, “执行阶段”:{ “阶段”:“获取”, “nReturned”:164, “executionTimeMillisEstimate”:120, “作品”:165, “高级”:164, “需要时间”:0, “需要产量”:0, “保存状态”:3, “恢复状态”:3, “isEOF”:1, “无效”:0, “docsExamined”:164, “已经有对象”:0, “输入阶段”:{ “阶段”:“IXSCAN”, “nReturned”:164, “执行时间MillisEstimate”:0, “作品”:165, “高级”:164, “需要时间”:0, “需要产量”:0, “保存状态”:3, “恢复状态”:3, “isEOF”:1, “无效”:0, “键模式”:{ “u_id”:1.0, “ts”:-1.0 }, “indexName”:“u_id_1_ts_-1”, “isMultiKey”:假, “isUnique”:假, “isSparse”:假, “isPartial”:假, “索引版本”:1, “方向”:“前进”, “索引边界”:{ “u_id”:[ "[\"USR-WOWU\",\"USR-WOWU\"]" ], “ts”:[ “[最大键,最小键]” ] }, “keysExamined”:164, “dupsTested”:0, “dupsDropped”:0, “seenInvalidated”:0 } }, “所有计划执行”:[] }, “服务器信息”:{ “主机”:“manish”, “端口”:22022, “版本”:“3.2.13”, “gitVersion”:“23899209cad60aaafe114f6aea6cb83025ff51bc” }, “好的”:1.0 }

请将上面的 JSON 和格式复制到任何编辑器中。

在上述查询之后,下一个相同的查询将在约 2 毫秒内响应。但是当我做很少的插入时,一分钟后会重复同样的事情。 (第一次查询需要时间+100ms,然后大约需要2ms。)

在我的 mongoDB 中是否缺少某些东西或需要配置任何东西?

【问题讨论】:

标签: mongodb performance


【解决方案1】:

为什么会这样

此日志行的docsExamined:10795hasSortStage:1 部分表明查询正在从磁盘扫描10,795,然后在内存中对结果进行排序。可以在here 找到解释日志行的指南。

indexing this query to avoid the in-memory sort 可能会提高性能。

对于这个查询,您应该尝试创建索引{ 'u_id' : 1, 'ts' : -1 }

如果我按降序更改像 {ts: -1} 这样的索引真的值得吗?

索引可以从任一方向读取,因此索引顺序对于单字段索引并不是非常重要。但是,在compound indexes 中排序可能非常重要。

更新

基于解释计划,查询现在正确地使用索引从索引中按顺序读取结果,从而避免了内存排序。看起来这使查询中断了约 100 毫秒。

但是,此查询似乎不再使用 .skip(0).limit(1)。能否将这些重新添加并查看性能是否有所提高?

您的部署似乎没有任何问题;对于未完全编入索引的查询,这种行为似乎很正常。

重新运行完全相同的查询会很快,因为现有结果(“the working set”)已经存储在内存中。插入新数据会使查询结果发生变化,这意味着结果可能需要再次读回内存。

【讨论】:

  • 我已经用 -1 重建索引(仅字段索引),但仍然出现问题。现在我将尝试复合索引,然后让你知道发生了什么...... :)
  • 没什么改善!!我已经完成了以下索引第一次尝试:{u_id:1} {ts:1} 第二次尝试:{u_id:1} {ts:-1} 第三次尝试:{u_id:1} {ts:-1} {u_id: 1、ts:-1};;第 4 次尝试:{u_id: 1} {ts: 1} {u_id: 1, ts: -1}.......
  • @ManishTrivedi 在第四次尝试中,使用复合索引{u_id: 1, ts: -1},应该会有所作为。 explain 有什么不同吗?
  • @ManishTrivedi 既然这些索引已经建立,你能分享一个新的日志行吗?正如文斯建议的那样,运行解释也有助于确定数据库如何使用索引
  • 非常感谢您的帮助! :) :) 我添加了有问题的查询计划程序日志。这次我只尝试了复合索引。 (我需要更多关于范围搜索的索引字段,但稍后再做。首先我想解决这个问题......:()
猜你喜欢
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
  • 2018-01-10
  • 2018-01-08
  • 2019-11-14
  • 2012-09-03
  • 2013-07-11
相关资源
最近更新 更多