我对查找查询的响应时间太长有疑问。
这很奇怪,因为如果我自己运行查询(例如通过 dataGrip / Intellij 驱动程序),响应时间约为 500-700 毫秒,而当它由使用 spring data mongo 的服务执行时,响应时间为 33000毫秒到 45000 毫秒
不仅时间不同——而且使用
.explain(“executionStats”)
更具体地验证查询——keysExamined
和docsExamined
的数量。
这是查询:
db.fooCollection.find({
"$or": [{
"$and": [{
"params": {
"$elemMatch": {
"name": "manufacturer",
"val": "FooManufacturer"
}
}
}, {
"params": {
"$elemMatch": {
"name": "articleId",
"val": "FOO-FOO-ARTICLE-ID-FOO"
}
}
}]
}, {
"$and": [{
"params": {
"$elemMatch": {
"name": "brand",
"val": "FooManufacturer"
}
}
}, {
"params": {
"$elemMatch": {
"name": "articleId",
"val": "FOO-FOO-ARTICLE-ID-FOO"
}
}
}]
}]
}).collation({
locale: 'en',
strength: 1,
alternate: "shifted",
maxVariable: "punct"
})
.explain("executionStats")
这是手动查询运行的
executionStats
:
{
"executionSuccess": true,
"nReturned": new NumberInt("1"),
"executionTimeMillis": new NumberInt("2"),
"totalKeysExamined": new NumberInt("1"),
"totalDocsExamined": new NumberInt("1"),
"executionStages": {
"stage": "SUBPLAN",
"nReturned": new NumberInt("1"),
"executionTimeMillisEstimate": new NumberInt("2"),
"works": new NumberInt("2"),
"advanced": new NumberInt("1"),
"needTime": new NumberInt("0"),
"needYield": new NumberInt("0"),
"saveState": new NumberInt("0"),
"restoreState": new NumberInt("0"),
"isEOF": new NumberInt("1"),
"inputStage": {
"stage": "FETCH",
"filter": {
"$or": [{
"$and": [{
"params": {
"$elemMatch": {
"$and": [{
"name": {
"$eq": "articleId"
}
}, {
"val": {
"$eq": "FOO-FOO-ARTICLE-ID-FOO"
}
}]
}
}
}, {
"params": {
"$elemMatch": {
"$and": [{
"name": {
"$eq": "brand"
}
}, {
"val": {
"$eq": "FooManufacturer"
}
}]
}
}
}]
}, {
"$and": [{
"params": {
"$elemMatch": {
"$and": [{
"name": {
"$eq": "articleId"
}
}, {
"val": {
"$eq": "FOO-FOO-ARTICLE-ID-FOO"
}
}]
}
}
}, {
"params": {
"$elemMatch": {
"$and": [{
"name": {
"$eq": "manufacturer"
}
}, {
"val": {
"$eq": "FooManufacturer"
}
}]
}
}
}]
}]
},
"nReturned": new NumberInt("1"),
"executionTimeMillisEstimate": new NumberInt("0"),
"works": new NumberInt("2"),
"advanced": new NumberInt("1"),
"needTime": new NumberInt("0"),
"needYield": new NumberInt("0"),
"saveState": new NumberInt("0"),
"restoreState": new NumberInt("0"),
"isEOF": new NumberInt("1"),
"docsExamined": new NumberInt("1"),
"alreadyHasObj": new NumberInt("0"),
"inputStage": {
"stage": "IXSCAN",
"nReturned": new NumberInt("1"),
"executionTimeMillisEstimate": new NumberInt("0"),
"works": new NumberInt("2"),
"advanced": new NumberInt("1"),
"needTime": new NumberInt("0"),
"needYield": new NumberInt("0"),
"saveState": new NumberInt("0"),
"restoreState": new NumberInt("0"),
"isEOF": new NumberInt("1"),
"keyPattern": {
"params.name": new NumberInt("1"),
"params.val": new NumberInt("1")
},
"indexName": "params.name_1_params.val_1",
"collation": {
"locale": "en",
"caseLevel": false,
"caseFirst": "off",
"strength": new NumberInt("1"),
"numericOrdering": false,
"alternate": "shifted",
"maxVariable": "punct",
"normalization": false,
"backwards": false,
"version": "57.1"
},
"isMultiKey": true,
"multiKeyPaths": {
"params.name": ["params"],
"params.val": ["params"]
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": new NumberInt("2"),
"direction": "forward",
"indexBounds": {
"params.name": ["[CollationKey(0xCOLLECTION_KEY), CollationKey(0xCOLLECTION_KEY)]"],
"params.val": ["[CollationKey(0xCOLLECTION_KEY_2), CollationKey(0xCOLLECTION_KEY_2)]"]
},
"keysExamined": new NumberInt("1"),
"seeks": new NumberInt("1"),
"dupsTested": new NumberInt("1"),
"dupsDropped": new NumberInt("0")
}
}
}
}
这很有趣-来自服务日志(相同的查询,相同的数据库,执行中使用的相同索引)
"planSummary":
"IXSCAN { params.name: 1, params.val: 1 }, IXSCAN { params.name: 1, params.val: 1 }",
"keysExamined": 87182,
"docsExamined": 87182,
"cursorExhausted": true,
"numYields": 484,
"nreturned": 1,
相同查询的结果在每种情况下都是不同的(服务与手动运行)。我尝试在 dataGrip 中使用较旧版本的 mongo 驱动程序,因为我认为它可能在服务中已经过时,这就是为什么需要这么长时间才能收到答案 - 但没有。依然是手工制作精准快速
这是代码中的方法:
private suspend fun findByParams(parameters: Set < Map < ParamName, ParamValue >> ): CloseableIterator < ProductDocument > {
val collation = Collation.of("en").strength(1).alternate("shifted").maxVariable("punct")
val query = Query().collation(collation)
val criterias = parameters.map {
set - > set.map {
Criteria.where("parameters").elemMatch(Criteria.where("name").iseEqualTo(it.key.name).and("value").isEqualTo(it.value.value))
}
}
query.addCriteria(Criteria().orOperator(criterias.mapNotNull {
Criteria().andOperator(it)
}))
return withContext(Dispatchers.IO) {
mongoTemplate.stream(query, ProductDocument::class.java)
}
}