【问题标题】:MongoDb search performanceMongoDb 搜索性能
【发布时间】:2014-07-31 14:07:41
【问题描述】:

我想知道为什么 mongo db (C#) 中的后续搜索需要 50 秒才能执行。

我遵循http://calv.info/indexing-schemaless-documents-in-mongo/的基本思路

我在一个集合中有 100,000 条记录(捕获)。在每个文档上我都有一个 SearchTerm Collection

public class SearchTerm
{
    public string Key { get; set; }
    public object Value { get; set; }
}

public class Capture
{
    //Some other fields
    public IList<SearchTerm> SearchTerms { get; set; }
}

我也定义了这样的索引

var capturesCollection = database.GetCollection<Capture>("captures");
capturesCollection.CreateIndex("SearchTerms.Key", "SearchTerms.Value");

但是下面的查询需要 50 秒才能执行

var query = Query.Or(Query.And(Query.EQ("SearchTerms.Key", "ClientId"), Query.EQ("SearchTerms.Value", selectedClient.Id)), Query.And(Query.EQ("SearchTerms.Key", "CustomerName"), Query.EQ("SearchTerms.Value", "Jan")));
var selectedCapture = capturesCollection.Find(query).ToList();

编辑:按照我的解释:

clauses: [{ "cursor" : "BtreeCursor SearchTerms.Key_1_SearchTerms.Value_1", "isMultiKey" : true, "n" : 10003, "nscannedObjects" : 100000, "nscanned" : 100000, "scanAndOrder" : false, "indexOnly" : false, "nChunkSkips" : 0, "indexBounds" : { "SearchTerms.Key" : [["ClientId", "ClientId"]], "SearchTerms.Value" : [[{ "$minElement" : 1 }, { "$maxElement" : 1 }]] } }, { "cursor" : "BtreeCursor SearchTerms.Key_1_SearchTerms.Value_1", "isMultiKey" : true, "n" : 70328, "nscannedObjects" : 90046, "nscanned" : 211653, "scanAndOrder" : false, "indexOnly" : false, "nChunkSkips" : 0, "indexBounds" : { "SearchTerms.Key" : [["CustomerName", "CustomerName"]], "SearchTerms.Value" : [[{ "$minElement" : 1 }, { "$maxElement" : 1 }]] } }]
cursor: QueryOptimizerCursor
n: 73219
nscannedObjects: 190046
nscanned: 311653
nscannedObjectsAllPlans: 190046
nscannedAllPlans: 311653
scanAndOrder: false
nYields: 2436
nChunkSkips: 0
millis: 5196
server: piro-pc:27017
filterSet: false
stats: { "type" : "KEEP_MUTATIONS", "works" : 311655, "yields" : 2436, "unyields" : 2436, "invalidates" : 0, "advanced" : 73219, "needTime" : 238435, "needFetch" : 0, "isEOF" : 1, "children" : [{ "type" : "OR", "works" : 311655, "yields" : 2436, "unyields" : 2436, "invalidates" : 0, "advanced" : 73219, "needTime" : 238435, "needFetch" : 0, "isEOF" : 1, "dupsTested" : 80331, "dupsDropped" : 7112, "locsForgotten" : 0, "matchTested_0" : 0, "matchTested_1" : 0, "children" : [{ "type" : "FETCH", "works" : 100001, "yields" : 2436, "unyields" : 2436, "invalidates" : 0, "advanced" : 10003, "needTime" : 89997, "needFetch" : 0, "isEOF" : 1, "alreadyHasObj" : 0, "forcedFetches" : 0, "matchTested" : 10003, "children" : [{ "type" : "IXSCAN", "works" : 100000, "yields" : 2436, "unyields" : 2436, "invalidates" : 0, "advanced" : 100000, "needTime" : 0, "needFetch" : 0, "isEOF" : 1, "keyPattern" : "{ SearchTerms.Key: 1, SearchTerms.Value: 1 }", "boundsVerbose" : "field #0['SearchTerms.Key']: [\"ClientId\", \"ClientId\"], field #1['SearchTerms.Value']: [MinKey, MaxKey]", "isMultiKey" : 1, "yieldMovedCursor" : 0, "dupsTested" : 100000, "dupsDropped" : 0, "seenInvalidated" : 0, "matchTested" : 0, "keysExamined" : 100000, "children" : [] }] }, { "type" : "FETCH", "works" : 211654, "yields" : 2436, "unyields" : 2436, "invalidates" : 0, "advanced" : 70328, "needTime" : 141325, "needFetch" : 0, "isEOF" : 1, "alreadyHasObj" : 0, "forcedFetches" : 0, "matchTested" : 70328, "children" : [{ "type" : "IXSCAN", "works" : 211653, "yields" : 2436, "unyields" : 2436, "invalidates" : 0, "advanced" : 90046, "needTime" : 121607, "needFetch" : 0, "isEOF" : 1, "keyPattern" : "{}", "boundsVerbose" : "field #0['SearchTerms.Key']: [\"CustomerName\", \"CustomerName\"], field #1['SearchTerms.Value']: [MinKey, MaxKey]", "isMultiKey" : 1, "yieldMovedCursor" : 0, "dupsTested" : 211653, "dupsDropped" : 121607, "seenInvalidated" : 0, "matchTested" : 0, "keysExamined" : 211653, "children" : [] }] }] }] }

【问题讨论】:

  • 请在查询上运行.explain()(alernerdev 的答案中有更详细的说明)并为我们发布输出。
  • @wdberkeley 谢谢,看看我的编辑

标签: mongodb mongodb-.net-driver


【解决方案1】:

感谢您发布解释。让我们一次解决一个问题。

首先,我不认为这个查询做你认为它做/希望它做的事情。让我通过示例向您展示使用 mongo shell。你的查询,翻译成外壳,是

{ "$or" : [
    { "$and" : [
        { "SearchTerms.Key" : "ClientId" }, 
        { "SearchTerms.Value" : "xxx" }
    ]},
    { "$and" : [
        { "SearchTerms.Key" : "CustomerName" },     
        { "SearchTerms.Value" : "Jan" }
    ]}
]}

此查询查找文档,其中一些 Key 的值为“ClientId”,一些 Value 的值为“xxx”,或者一些 Key 的值为“CustomerName”,一些 Value 的值为“Jan” ”。 键和值不需要是同一个数组元素的一部分。例如,以下文档与您的查询匹配

{ "SearchTerms" : [
        { "Key" : "ClientId", "Value" : 691 }, 
        { "Key" : "banana", "Value" : "xxx" }
    ]
}

我猜你想要的行为是完全匹配在同一数组元素中包含 KeyValue 的文档。 $elemMatch 运算符是完成这项工作的工具:

{ "$or" : [
    { "SearchTerms" : { "$elemMatch" : { "Key" : "ClientId", "Value" : "xxx" } } },
    { "SearchTerms" : { "$elemMatch" : { "Key" : "CustomerName", "Value" : "Jan" } } }
]}

其次,我不认为这个架构是您正在寻找的。你没有描述你的用例,所以我不能自信,但该博客文章中描述的情况是一种非常罕见的情况,你需要存储和搜索 任意 键值对可以从一个文档更改为下一个文档。这就像让用户输入自定义元数据一样。几乎没有应用程序想要或需要这样做。看起来您的应用程序正在存储有关客户的信息,可能用于内部系统。您应该能够为您的客户定义一个data model,看起来像

{
    "CustomerId" : 1234,
    "CustomerName" : "Jan",
    "ClientId" : "xpj1234",
    ...
}

这将大大简化和改进事情。我认为这里的电线被越过了,因为有时人们称 MongoDB 为“无模式”,而博客文章谈到了“无模式”文档。该博客文章实际上是在谈论您不知道其中会发生什么的无模式文档。大多数应用程序应该非常准确地知道集合中文档的一般结构。

最后,我认为基于此我们可以暂时忽略慢查询的问题。如果您需要更多帮助,或者在您考虑到我在此处所说的内容后问题仍未消失,请随时提出另一个问题或编辑此问题并提供额外解释。

【讨论】:

  • 感谢您的帮助。在第一点你是对的。我想要 elemMatch 给出的结果。但是关于你的第二点。我的确切情况是我不知道文档将包含哪些数据(这是因为数据是使用第三方创建的工作流程收集的)。因此,我选择使用链接中建议的模型。我猜我的查询更改为 elemMatch 不会解决我的性能问题?
  • 在另一篇文章中,您还评论了这个想法是如何发现添加了哪些新字段,然后将这些字段索引为新文档包含新字段但是考虑到我认为数据的动态性质帖子中使用的模式是更好的方法吗? (我特别选择了 MongoDb,因为它能够处理非结构化数据)
【解决方案2】:

1) 请查看 mongodb 日志文件并查看针对数据库生成的查询。 2)将该查询输入mongo shell并在最后添加“.explain()” - 看看您的索引是否实际被使用(它是说Basic Cursor还是Btree Cursor?) 3) 如果使用您的索引,“nscanned”属性的值是多少?也许您的索引中没有足够的“价值多样性”?

【讨论】:

  • 311653。不知道这告诉我什么。查看我的编辑
  • 这告诉您的是,您的索引虽然被使用,但效率低下。如果您的索引是有效的,那么您的 nScanned 值会很小(可能是个位数)。想象一下存储人物,并索引眼睛颜色。虽然您可以快速找到“hazel”存储桶,但您必须扫描数百万条记录来寻找您要找的人。你也有类似的情况。有关更多信息,请参阅此内容:jira.mongodb.org/browse/DOCS-3187
猜你喜欢
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-16
  • 2019-11-25
  • 1970-01-01
相关资源
最近更新 更多