0

在我的 mongodb 集合中,我有 1500 万个具有以下 json 结构的文档。每个 json 文档的 playfields 数组字段中的嵌入文档计数都会发生变化。我所有的查询都涉及根据 playfields 数组字段中的数据过滤文档。所有查询的执行时间都超过 2 分钟。

嵌入文档中的 value 字段存储多种数据类型(int、string)。这是糟糕的设计吗?

我在写查询时做错了吗?我是否缺少任何索引?我是否必须将数据从单个文档中的嵌入文档移动到多个集合?

多条件查询(有问题发布)需要 3 分钟才能执行。过滤同一集合时使用的语法是否错误?我的目标是返回满足所有这些条件的文档。

如果我将查询分成几部分,则每个都需要 ms 才能执行。1) db.playfieldvalues.find({$or:[ {playfields: {$elemMatch:{ID:"Play.NHL.NHLAwayTeam" ,value: "NYI NEW YORK ISLANDERS"}}},{playfields: {$elemMatch: {ID:"Play.NHL.NHLAwayTeam" ,value:"TB TAMPA BAY LIGHTNING"}}}]}) 2) db.playfieldvalues.find({playfields: {$elemMatch:{ID:"Play.NHL.NHLHomeTeam" ,value: "BOS BOSTON BRUINS"}}}) 3) db.playfieldvalues.find({playfields: {$elemMatch:{ID:"Play.NHL.NHLEventX" ,value: {$gt: 0, $lt: 25 }}}}) 4) db.playfieldvalues.find({playfields: {$elemMatch:{ID:"Play.NHL.NHLEventScoreDifferential" ,value: {$gt: 0}}}})

在此处输入图像描述 在此处输入图像描述

创建的索引:

db.collection.ensureIndex({ "playfields.ID": 1, "playfields.value": 1 })

查询运行:

1:

db.playfieldvalues.find({playfields: {$elemMatch:{ID:"Play.NHL.NHLHomeTeam" ,value: "BOS BOSTON BRUINS"}}})

2:

db.playfieldvalues.find({$and:[
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLHomeTeam" ,value: "BOS BOSTON BRUINS"}}},
  {$or:[ {playfields: {$elemMatch:{ID:"Play.NHL.NHLAwayTeam" ,value: "NYI NEW YORK ISLANDERS"}}},{playfields: {$elemMatch:{ID:"Play.NHL.NHLAwayTeam" ,value: "T.B TAMPA BAY LIGHTNING"}}}]},
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLEventY" ,value: -38}}},
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLEventX" ,value: {$gt: 0}}}},
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLEventScoreDifferential" ,value: {$gt: 0}}}}
  ]
})

JSON 文档示例:

{ 
    "_id" : ObjectId("59dbd4c5704aa82e70ac10b5"), 
    "playid" : "2594c658-aa3b-4a98-b2eb-0cc03e4dc9e5", 
    "playfields" : [
        {
            "ID" : "Play.NHL.NHLGameDate", 
            "TS" : "", 
            "value" : NumberInt(20160228)
        }, 
        {
            "ID" : "Play.GameDate", 
            "TS" : "", 
            "value" : "2/28/2016 12:00:00 AM"
        }, 
        {
            "ID" : "Play.NHL.NHLEventType", 
            "TS" : "", 
            "value" : "HIT"
        }, 
        {
            "ID" : "Play.NHL.NHLClockTime", 
            "TS" : "", 
            "value" : "03:08"
        }, 
        {
            "ID" : "Play.NHL.NHLClockTimeSeconds", 
            "TS" : "", 
            "value" : NumberInt(188)
        }, 
        {
            "ID" : "Play.NHL.NHLEventX", 
            "TS" : "", 
            "value" : NumberInt(62)
        }, 
        {
            "ID" : "Play.NHL.NHLEventY", 
            "TS" : "", 
            "value" : NumberInt(-38)
        }, 
        {
            "ID" : "Play.NHL.NHLEventPeriod", 
            "TS" : "", 
            "value" : "1"
        }, 
        {
            "ID" : "Play.NHL.NHLGameCode", 
            "TS" : "", 
            "value" : "20933"
        }, 
        {
            "ID" : "Play.NHL.NHLSeason", 
            "TS" : "", 
            "value" : "20152016"
        }, 
        {
            "ID" : "Play.NHL.NHLHomeTeam", 
            "TS" : "", 
            "value" : "BOS BOSTON BRUINS"
        }, 
        {
            "ID" : "Play.NHL.NHLAwayTeam", 
            "TS" : "", 
            "value" : "T.B TAMPA BAY LIGHTNING"
        }, 
        {
            "ID" : "Play.NHL.NHLPrimaryTeam", 
            "TS" : "", 
            "value" : "T.B TAMPA BAY LIGHTNING"
        }, 
        {
            "ID" : "Play.NHL.NHLPrimaryTeamActionPlayer", 
            "TS" : "", 
            "value" : "e27ca5e6-d4fa-4d45-8fa2-a860f64f7ea7"
        }, 
        {
            "ID" : "Play.NHL.NHLSecondaryTeam", 
            "TS" : "", 
            "value" : "BOS BOSTON BRUINS"
        }, 
        {
            "ID" : "Play.NHL.NHLSecondaryTeamActionPlayer", 
            "TS" : "", 
            "value" : "bea1deb6-aabd-47e8-b216-6f4df5f1ea97"
        }, 
        {
            "ID" : "Play.NHL.NHLEventZone", 
            "TS" : "", 
            "value" : "DZ"
        }, 
        {
            "ID" : "Play.NHL.NHLEventScoreDifferential", 
            "TS" : "", 
            "value" : NumberInt(1)
        }, 
        {
            "ID" : "Play.NHL.NHLEventStrength", 
            "TS" : "", 
            "value" : "Even"
        }
    ]
}

附加第二个查询的解释输出: 在此处输入图像描述 在此处输入图像描述

在此处输入图像描述

4

1 回答 1

0

嵌入文档中的 value 字段存储多种数据类型(int、string)。这是糟糕的设计吗?

如果您亲自问我,来自 java 背景,是的,这是一个糟糕的设计。但是对于 MongoDB,这并不是一个真正的问题,只要您的应用程序可以处理它。仅供参考,您的索引大小也应该很大,您可以通过 来检查db.playfieldvalues.stats(),但这也无关紧要。至少它与您的性能问题无关。

我在写查询时做错了吗?

嗯,查询有点复杂,需要满足很多条件。您还可以使用 $or 运算符将查询更改为

db.playfieldvalues.find({
$and:[
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLHomeTeam" ,value: "BOS BOSTON BRUINS"}}},
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLAwayTeam" ,value: {$in: ["NYI NEW YORK ISLANDERS", "T.B TAMPA BAY LIGHTNING"]}}}},
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLEventY" ,value: -38}}},
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLEventX" ,value: {$gt: 0}}}},
  {playfields: {$elemMatch:{ID:"Play.NHL.NHLEventScoreDifferential" ,value: {$gt: 0}}}}
  ]
})

尽量简化您的查询参数。甚至可能与您合作,.limit(n)并且.skip(n)是一个更好的解决方案。

我是否缺少任何索引?

看看这篇文章,虽然它可能是旧的,但它可能是相关的。 多键索引上的慢范围查询

但是在您继续删除并创建新索引之前,请尝试删除查询的某些部分以尝试找出可能导致它的确切原因。例如,我会删除这些行:

{playfields: {$elemMatch:{ID:"Play.NHL.NHLEventX" ,value: {$gt: 0}}}},
{playfields: {$elemMatch:{ID:"Play.NHL.NHLEventScoreDifferential"
,value: {$gt: 0}}}}

并检查性能是否仍然相同。查看文档 docs.mongodb.com/manual/core/multikey-index-bounds 。查看您的 indexBounds -> playfields.ID 和 playfields.value。我不确定为什么 playfields.value: (0.0, 25.0)。在文档中它说评级的界限: { $gte: 0 } 谓词是 [ [ 0, Infinity ] ]

我是否必须将数据从单个文档中的嵌入文档移动到多个集合?

不,你不必。没有固定的模式,你可以随心所欲。

关于如何检查您是否使用wiredTiger的评论中的问题:db.serverStatus().storageEngine。但是由于您使用的是 mongo 3.4.9 版,因此您使用的是wiredTiger

于 2017-10-16T19:50:57.860 回答