解读 mongoDB 日志,给出优化建议
2024-08-10T11:11:34.917+0800 I COMMAND [conn1543] command testDB.T_Test command: find { find: "T_Test", filter: { $and: [ { code: "48067410" }, { eid: "25404104" } ] }, limit: 1, singleBatch: true } planSummary: COLLSCAN keysExamined:0 docsExamined:40387 cursorExhausted:1 numYields:652 nreturned:1 reslen:294 locks:{ Global: { acquireCount: { r: 1306 } }, Database: { acquireCount: { r: 653 } }, Collection: { acquireCount: { r: 653 } } } protocol:op_query 11775ms
2024-08-10T11:11:36.361+0800 I COMMAND [conn1570] command testDB.T_Test command: find { find: "T_Test", filter: { $and: [ { code: "48071282" }, { eid: "25404104" } ] }, limit: 1, singleBatch: true } planSummary: COLLSCAN keysExamined:0 docsExamined:39292 cursorExhausted:1 numYields:615 nreturned:1 reslen:125622 locks:{ Global: { acquireCount: { r: 1232 } }, Database: { acquireCount: { r: 616 } }, Collection: { acquireCount: { r: 616 } } } protocol:op_query 10933ms
2024-08-10T11:11:40.204+0800 I COMMAND [conn1635] command testDB.T_Test command: find { find: "T_Test", filter: { $and: [ { code: "48049044" }, { eid: "25404104" } ] }, limit: 1, singleBatch: true } planSummary: COLLSCAN keysExamined:0 docsExamined:31716 cursorExhausted:1 numYields:485 nreturned:1 reslen:294 locks:{ Global: { acquireCount: { r: 972 } }, Database: { acquireCount: { r: 486 } }, Collection: { acquireCount: { r: 486 } } } protocol:op_query 8605ms
2024-08-10T11:11:34.917+0800 I COMMAND [conn1543] command testDB.T_Test command: find { find: "T_Test", filter: { $and: [ { code: "48067410" }, { eid: "25404104" } ] }, limit: 1, singleBatch: true } planSummary: COLLSCAN keysExamined:0 docsExamined:40387 cursorExhausted:1 numYields:652 nreturned:1 reslen:294 locks:{ Global: { acquireCount: { r: 1306 } }, Database: { acquireCount: { r: 653 } }, Collection: { acquireCount: { r: 653 } } } protocol:op_query 11775ms
这条 MongoDB 日志记录了一次 find
查询的执行情况。
让我们逐一解析这些字段的含义,并给出优化建议。
日志解读
1. 命令:
command testDB.T_Test command: find { find: "T_Test", filter: { $and: [ { code: "48067410" }, { eid: "25404104" } ] }, limit: 1, singleBatch: true }
-
testDB.T_Test: 指在
testDB
数据库中的T_Test
集合上执行的查询。 -
filter: 查询条件是
$and
连接的两个条件{ code: "48067410" }
和{ eid: "25404104" }
。 - limit: 1: 查询限制返回的文档数量为 1。
- singleBatch: true: 查询结果一次性返回,不进行分批。
2. 执行计划:
planSummary: COLLSCAN
- COLLSCAN: 查询计划使用了集合扫描(全表扫描),表示 MongoDB 在没有索引的情况下逐个扫描集合中的所有文档。
3. 扫描情况:
keysExamined: 0
docsExamined: 40387
cursorExhausted: 1
numYields: 652
nreturned: 1
reslen: 294
- keysExamined: 0: 扫描了 0 个索引键(因为没有使用索引)。
- docsExamined: 40387: 检查了 40387 个文档。
- cursorExhausted: 1: 光标扫描完毕。
- numYields: 652: 查询过程中发生了 652 次上下文切换(因为长时间运行,MongoDB 需要释放 CPU 给其他操作)。
- nreturned: 1: 返回了 1 个文档。
- reslen: 294: 响应的文档大小为 294 字节。
4. 锁信息:
locks:{ Global: { acquireCount: { r: 1306 } }, Database: { acquireCount: { r: 653 } }, Collection: { acquireCount: { r: 653 } } }
- Global: { acquireCount: { r: 1306 } }: 全局锁读取次数。
- Database: { acquireCount: { r: 653 } }: 数据库锁读取次数。
- Collection: { acquireCount: { r: 653 } }: 集合锁读取次数。
5. 执行时间:
11775ms
- 执行时间: 11775 毫秒,即 11.8 秒,表示该查询花费了较长时间。
优化建议
1. 添加索引
-
查询的条件是
{ code: "48067410", eid: "25404104" }
,因此可以在code
和eid
字段上创建复合索引。这样可以避免全表扫描,显著提高查询性能。db.T_Test.createIndex({ code: 1, eid: 1 });
2. 查询条件优化
- 确保
code
和eid
字段在查询条件中有合适的索引顺序。如果数据集很大,可以尝试在查询中使用更具选择性的字段作为第一个索引字段。
3. 分析数据分布
- 检查
code
和eid
字段的选择性。如果某些值非常频繁,可能需要重新评估索引策略或考虑使用其他字段。
4. 确保服务器性能
- 确保 MongoDB 服务器的性能,如内存、CPU 和 I/O 等资源充足。长时间的全表扫描可能会因服务器资源不足而变得更加缓慢。
5. 使用 MongoDB 管理工具
- 使用 MongoDB 自带的分析工具(如
explain
)来验证索引的效果,并监控数据库性能以进行进一步优化。
通过添加索引和优化查询条件,可以显著减少扫描的文档数量和查询的执行时间。
$ mongo --host xx.xx.xx.xx -u yzjuser -p 'XXXXXX' --port 27017 --authenticationDatabase admin
> use testDB
> db.T_Test.count()
70181
> db.T_Test.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "testDB.T_Test"
}
]
在 MongoDB 中,索引的创建操作可以通过后台模式来执行,以避免对数据库操作的影响。后台模式的索引创建可以使 MongoDB 在后台线程中创建索引,从而减少对数据库主线程的影响。
请注意,在 MongoDB 4.2 及以前版本中,创建索引时可以使用 background 选项,但在 MongoDB 4.4 及之后版本,索引创建默认就是后台模式,不需要显式指定。
如果你使用的是 MongoDB 4.2 及以前版本,你可以通过以下方式在后台创建索引:
> db.T_Test.createIndex({ code: 1, eid: 1 }, { background: true })
检查索引效果
创建索引后,可以使用 explain 方法来检查查询是否在使用新的索引。例如:
> db.T_Test.find({ code: "48067410", eid: "25404104" }).explain("executionStats")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "testDB.T_Test",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"code" : {
"$eq" : "48067410"
}
},
{
"eid" : {
"$eq" : "25404104"
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"eid" : 1,
"code" : 1
},
"indexName" : "eid_code_idx",
"isMultiKey" : false,
"multiKeyPaths" : {
"eid" : [ ],
"code" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"eid" : [
"[\"25404104\", \"25404104\"]"
],
"code" : [
"[\"48067410\", \"48067410\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 0,
"executionTimeMillis" : 0,
"totalKeysExamined" : 0,
"totalDocsExamined" : 0,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 0,
"executionTimeMillisEstimate" : 0,
"works" : 1,
"advanced" : 0,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 0,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 0,
"executionTimeMillisEstimate" : 0,
"works" : 1,
"advanced" : 0,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"eid" : 1,
"code" : 1
},
"indexName" : "eid_code_idx",
"isMultiKey" : false,
"multiKeyPaths" : {
"eid" : [ ],
"code" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"eid" : [
"[\"25404104\", \"25404104\"]"
],
"code" : [
"[\"48067410\", \"48067410\"]"
]
},
"keysExamined" : 0,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "localhost",
"port" : 27017,
"version" : "3.4.19",
"gitVersion" : "a2d97db8fe449d15eb8e275bbf318491781472bf"
},
"ok" : 1
}
这会提供详细的查询执行计划,帮助你验证索引是否被有效使用。
网友评论