Json Mongodb过滤嵌入大数组文档时的查询性能
在我的mongodb集合中,我有1500万个具有以下json结构的文档。每个json文档的playfields数组中嵌入的文档数都会发生变化。我的所有查询都涉及根据playfields数组中的数据过滤文档。所有查询的执行时间都超过2分钟 嵌入文档中的值字段存储多个数据类型(int、string)。这个设计不好吗 我在写问题时有没有做错什么?我是否缺少任何索引?是否必须将数据从单个文档中的嵌入文档移动到多个集合 多条件查询(有问题的发布)需要3分钟才能执行。过滤同一集合时使用的语法是否错误?我的目标是返回满足所有这些条件的文档 如果我将查询分解为多个部分,每个部分都需要ms来执行。 1) db.playfieldvalues.find({$or:[{$playfields:{$elemMatch:{ID:“Play.NHL.NHLAwayTeam”,value:“纽约岛居民”}}}}},{playfields:{$elemMatch:{ID:“Play.NHL.NHLAwayTeam”,value:“坦帕湾闪电队”}}}) 2) db.playfieldvalues.find({playfields:{$elemMatch:{ID:“Play.NHL.NHLHomeTeam”,value:“BOS BOSTON BRUINS”}}}) 3) 查找({playfields:{$elemMatch:{ID:“Play.NHL.NHLEventX”,值:{$gt:0,$lt:25}}}) 4) 查找({playfields:{$elemMatch:{ID:“Play.NHL.NHLEventScoreDifferential”,值:{$gt:0}}) 已创建索引:Json Mongodb过滤嵌入大数组文档时的查询性能,json,mongodb,nosql,nosql-aggregation,Json,Mongodb,Nosql,Nosql Aggregation,在我的mongodb集合中,我有1500万个具有以下json结构的文档。每个json文档的playfields数组中嵌入的文档数都会发生变化。我的所有查询都涉及根据playfields数组中的数据过滤文档。所有查询的执行时间都超过2分钟 嵌入文档中的值字段存储多个数据类型(int、string)。这个设计不好吗 我在写问题时有没有做错什么?我是否缺少任何索引?是否必须将数据从单个文档中的嵌入文档移动到多个集合 多条件查询(有问题的发布)需要3分钟才能执行。过滤同一集合时使用的语法是否错误?我的目
{
"_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"
}
]
}
db.collection.ensureIndex({“playfields.ID”:1,“playfields.value”:1})
正在运行的查询:
1:
2:
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"
}
]
}
附上第二次查询的解释输出:
嵌入式文档中的值字段存储多个数据类型(int,
字符串)。这个设计不好吗
如果你问我个人,来自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。查看您的索引边界->playfields.ID和playfields.value。我不知道为什么playfields.value:(0.0,25.0)。在文档中,它说评级:{$gte:0}谓词的边界是[[0,无穷]]
我是否必须将数据从单个文档中的嵌入文档移动到
多个集合
不,你不必。没有固定的模式,您可以随心所欲
关于如何检查您是否使用wiredTiger的评论中的问题:db.serverStatus().storageEngine。但因为您使用的是mongo 3.4.9版,所以您使用的是wiredTiger
嵌入式文档中的值字段存储多个数据类型(int,
字符串)。这个设计不好吗
如果你问我个人,来自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。查看您的索引边界->playfields.ID和playfields.value。我不知道为什么playfields.value:(0.0,25.0)。在文档中,它说评级:{$gte:0}谓词的边界是[[0,无穷]]
我是否必须将数据从单个文档中的嵌入文档移动到
多个集合
不,你不必。没有固定的模式,您可以随心所欲
关于如何检查您是否使用wiredTiger的评论中的问题:db.serverStatus().storageEngine。但是因为您使用的是mongo 3.4.9版,所以您使用的是wiredTiger我第一次使用Mongodb。我正在阅读有关索引和尝试的文章,但没有突破。有人能就这个问题给我一些建议吗?你使用的是什么版本的MongoDB?您正在使用WiredTiger存储引擎吗?我还要在查询的末尾添加.explain()。示例:db.playfieldvalues.find({playfields:{$elemMatch:{ID:“Play.NHL.NHLHomeTeam”,value:“BOS BOSTON BRUINS”}}}}).explain();如果获胜的计划阶段是FETCH,那么IXSCAN意味着它使用您的索引。你也可以看一看