在过滤嵌入大型数组文件时查询性能Mongodb

时间:2017-10-13 19:16:34

标签: json mongodb nosql nosql-aggregation

在我的mongodb集合中,我有1500万个具有以下json结构的文档。 playfields数组字段内的嵌入文档计数会针对每个json文档进行更改。我的所有查询都涉及根据playfields数组字段中的数据过滤文档。所有查询都需要超过2分钟才能执行。

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

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

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

如果我将查询分解成片段,则每次执行ms。 1)db.playfieldvalues.find({$或:[{playfields:{$ elemMatch:{ID:“Play.NHL.NHLAwayTeam”,value:“NYI NEW YORK ISLANDERS”}}},{playfields:{$ elemMatch: {ID:“Play.NHL.NHLAwayTeam”,价值:“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}}}})

enter image description here enter image description here

已创建索引:

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"
        }
    ]
}

附加解释第二个查询的输出: enter image description here enter image description here

enter image description here

1 个答案:

答案 0 :(得分:0)

  

嵌入式文档中的值字段存储多种数据类型(int,   串)。这是一个糟糕的设计吗?

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

  

我在编写查询时做错了吗?

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

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)也可以为您提供更好的解决方案。

  

我错过了任何索引吗?

看看这篇文章,虽然它可能是相关的旧版本。 Slow range query on a multikey index

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

{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