【问题标题】:MongoDB - performance and collection sizeMongoDB - 性能和集合大小
【发布时间】:2016-01-25 22:48:27
【问题描述】:

我有一个关于集合大小和查询性能的问题 –

有 2 个 db——DB1 和 DB2。 DB1 有 1 个集合,这是 stats() 对这个集合的输出——

{
    …
   "count" : 2085217,
    "size" : 17048734192,
    "avgObjSize" : 8176,
    "capped" : false,
    "nindexes" : 3,
    "indexDetails" : {},
    "totalIndexSize" : 606299456,
    "indexSizes" : {
        "_id_" : 67664576,
        "id_1" : 284165056,
        "id_2" : 254469824
    },
…
}

使用索引 id_1 对该集合的查询在 0.012 秒内返回。这是 explain() 的输出 -

"executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1,
        "executionTimeMillis" : 0,
        "totalKeysExamined" : 1,
        "totalDocsExamined" : 1, 
       ….
                "indexName" : "id_1",
            }

在 DB2 中,我有 4 个集合,这是 DB2 上的 stats 的输出 -

{
    …
    "collections" : 4,
    "objects" : 152655935,
    "avgObjSize" : 8175.998307514215,
    "dataSize" : 1248114666192,
    "storageSize" : 1257144933456,
    "indexes" : 12,
    "indexSize" : 19757688272,
    "fileSize" : 1283502112768,
…
}

使用索引对 DB2 中的任何集合进行查询(我通过 explain() 确认)所花费的时间至少是上一次针对 DB1 查询所用时间的两倍。

既然 mongo 应该可以很好地扩展,为什么会有这种差异?我读到 mongodb 将所有索引加载到内存中,并且由于 DB2 的容量比 DB1 大,这就是为什么它需要更长的时间吗?

任何见解都会非常有帮助。谢谢。

编辑 1: 添加更多信息。集合定义、索引定义和执行的查询...

所有集合(在两个数据库中)都包含相同的字段;它们之间只有文档的值和大小不同。

还有,这是相关的索引 -

"1" : {
     "v" : 1,
     "unique" : true,
     "key" : {
        "id" : 1
     },
     "name" : "id_1",
     "ns" : "ns.coll1"
   }

而且,这就是 id 字段的样子:

"_id" : ObjectId("55f9b6548aefbce6b2fa2fac"),
"id" : {
   "pid" : {
    "f1" : "val1",
    "f2" : "val2"
   }
},

还有,这是一个示例查询 -

db.coll1.find({id:{pid:{f1:"val1",f2:"val2"}}})

编辑 2: 以下是有关硬盘和 RAM 的更多信息 -

$ free -m
              total        used        free      shared  buff/cache   available
Mem:         386758        3750        1947       25283      381060      355675
Swap:        131071        3194      127877

硬盘3.5T左右,其中2.9T已经用完了。

【问题讨论】:

  • 你能提供更多细节吗?集合定义、索引定义和查询是否执行?
  • 我编辑了上面的原始帖子以添加更多信息。谢谢。
  • 如果没有足够的 RAM 存储热数据,查询会很慢,因为需要访问磁盘。
  • 我更新了我的帖子,包括内存信息。究竟什么是热点数据?它是查询所针对的整个集合,还是仅仅是索引?如果是后者,我是否应该确保 RAM 中的可用空间足够大以支持集合的 indexSize?谢谢。

标签: mongodb query-performance


【解决方案1】:

缩放

MongoDB 的扩展性非常好。问题是,它被设计为水平扩展,而不是垂直扩展。这意味着如果您的数据库拥有大量数据,您应该对集合进行分片以实现更好的并行化。

基准测试结果

关于查询时间的差异,我认为您的分析不是决定性的。数据库可能在不同的机器上(具有不同的规格)。假设硬件相同,DB2 显然在其集合中保存了更多文档,并且两个 DB 上的文档大小不一样。同一个查询可以返回不同大小的数据集。这将不可避免地对数据序列化和其他低级方面产生影响。除非您在更可控的设置中分析查询,否则我认为您的结果几乎是预期的。

建议

  • 如果您在文档上使用 DRef,请小心。它可能的 Mongo 会自动取消引用它们;这意味着要序列化和开销的数据更多。

  • 尝试使用limit 规范运行相同的查询。您已将索引定义为唯一的,但我不知道这是否会自动使 Mongo 在找到值后停止索引遍历。检查db.coll1.find({id:{pid:{f1:"val1",f2:"val2"}}})db.coll1.find({id:{pid:{f1:"val1",f2:"val2"}}}).limit(1) 是否同时运行。

  • 看看Indexes on embedded fieldsIndexes on embedded documents。嵌入文档似乎会减少额外的开销。

最后,如果您的文档没有嵌入的文档,只有嵌入的字段(似乎是这种情况),那么更具体地定义您的索引。创建这个索引

db.coll1.createIndex({"id.pid.f1": 1, "id.pid.f2": 1}, {unique: true})

然后再次运行查询。如果这个索引没有提高性能,那么我相信你已经做好了一切,可能是时候开始sharding了。

【讨论】:

  • 感谢您的详细回复。我的两个数据库都在同一台机器上,所以我们可以消除硬件不同。每个查询(针对两个数据库)应该只返回 1 个文档,因为我基本上只提供索引字段(它们是唯一的)作为查询参数。
  • 如您的定义所示,该索引是唯一的。但是文档只告诉我们 Mongo 使用它来强制数据一致性。如果您尝试插入非唯一值,则会失败。但是文档没有提到是否使用唯一性来优化查询。 Mongo 可能会找到您的文档,但仍会继续查询以查找其他文档。我认为情况并非如此。我相信 Mongo 实施得很好。但是您仍然应该尝试使用 limit(1) 以确保 Mongo 在有疑问时足够聪明。
  • 对不起,我之前的回复被切断了。回覆。其他建议 - 文档中没有 DRef;有或无限制运行(1)需要相似的时间来检索;并且数据集中没有嵌入的文档。另外,我确实有您提到的索引,并且我使用如下查询,以便它使用该索引,但性能是相同的。 db.coll1.find({"id:.pid.f1":"val1","id:.pid.f2":"val2"}}})
  • 那么你似乎没有做错任何事。也许问题确实是大索引破坏了您的 RAM。
  • 谢谢。分片似乎是要走的路。
猜你喜欢
  • 2012-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-26
  • 2019-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多