在我的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}}}})
已创建索引:
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"
}
]
}
答案 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