在 Azure Cosmos DB for MongoDB vCore 中编制索引的最佳做法
适用对象: MongoDB vCore
可查询字段应始终创建索引
基于谓词和聚合的读取操作会查阅相应筛选器的索引。 如果没有索引,数据库引擎将执行文档扫描以检索匹配的文档。 扫描的开销总是很高,随着集合中数据量的增长,扫描成本会越来越高。 为了获得最佳查询性能,应始终为所有可查询字段创建索引。
默认情况下,应避免编制不必要的索引和为所有字段编制索引
只应为可查询字段编制索引。 仅当查询模式不可预知时,才应使用通配符索引,其中文档结构中的任何字段都可以是查询筛选器的一部分。
提示
默认情况下,Azure Cosmos DB for MongoDB vCore 仅为 _id 字段编制索引。 默认情况下不会为所有其他字段编制索引。 应提前规划要编制索引的字段,以最大程度地提高查询性能,同时最大程度地减少编制过多字段的索引对写入造成的影响。
首次插入新文档或者更新或删除现有文档时,索引中的每个指定字段也会更新。 如果索引策略包含大量字段(或文档中的所有字段),服务器在更新相应索引时会消耗更多资源。 大规模运行时,只有可查询字段才应编制索引,而查询谓词中未使用的所有剩余字段都应从索引中排除。
在数据引入之前创建必要的索引
为了获得最佳性能,应在加载数据之前提前创建索引。 所有文档写入、更新和删除都将同步更新相应的索引。 如果在引入数据后创建索引,则会使用更多服务器资源为历史数据编制索引。 取决于历史数据的大小,此操作非常耗时,会影响稳定状态的读取和写入性能。
注意
对于读取模式发生变化且需要添加索引的场景,应启用后台索引,这可以通过支持工单完成。
对于针对历史数据创建的多个索引,请为每个字段发出非阻止的 createIndex 命令
并非总是可以提前规划所有查询模式,特别是在应用程序需求不断变化的情况下。 不断变化的应用程序需求不可避免地需要将字段添加到具有大量历史数据的群集上的索引中。
在这种情况下,应异步发出每个 createIndex 命令,而无需等待来自服务器的响应。
注意
默认情况下,Azure Cosmos DB for MongoDB vCore 仅在基于历史数据完全构建索引后响应 createIndex 操作。 取决于群集的大小和引入的数据量,这可能需要一段时间,并且看起来好像服务器没有响应 createIndex 命令。
如果通过 Mongo Shell 发出 createIndex 命令,请使用 Ctrl + C 中断命令以停止等待响应并发出下一组操作。
注意
在发出 createIndex 命令后,使用 Ctrl + C 中断该命令不会终止服务器上的索引生成操作。 它只会阻止 Shell 等待来自服务器的响应,而服务器则以异步方式继续基于现有文档生成索引。
为包含多个字段的谓词的查询创建复合索引
复合索引应在以下场景中使用:
- 包含针对多个字段的筛选器的查询
- 包含针对多个字段的筛选器且一个或多个字段按升序或降序排序的查询
请考虑“cosmicworks”数据库和“employee”集合中的以下文档
{
"firstName": "Steve",
"lastName": "Smith",
"companyName": "Microsoft",
"division": "Azure",
"subDivision": "Data & AI",
"timeInOrgInYears": 7
}
请考虑查找姓氏为“Smith”且司龄超过 5 年的所有员工的以下查询:
db.employee.find({"lastName": "Smith", "timeInOrgInYears": {"$gt": 5}})
“lastName”和“timeInOrgInYears”上的复合索引可优化此查询:
use cosmicworks;
db.employee.createIndex({"lastName" : 1, "timeInOrgInYears" : 1})
跟踪 createIndex 操作的状态
当添加索引并需要编制历史数据的索引时,可以使用 db.currentOp() 跟踪索引生成操作的进度。
请考虑跟踪“cosmicworks”数据库上的索引编制进度这个示例。
use cosmicworks;
db.currentOp()
当 createIndex 操作正在进行时,响应如下所示:
{
"inprog": [
{
"shard": "defaultShard",
"active": true,
"type": "op",
"opid": "30000451493:1719209762286363",
"op_prefix": 30000451493,
"currentOpTime": "2024-06-24T06:16:02.000Z",
"secs_running": 0,
"command": { "aggregate": "" },
"op": "command",
"waitingForLock": false
},
{
"shard": "defaultShard",
"active": true,
"type": "op",
"opid": "30000451876:1719209638351743",
"op_prefix": 30000451876,
"currentOpTime": "2024-06-24T06:13:58.000Z",
"secs_running": 124,
"command": { "createIndexes": "" },
"op": "workerCommand",
"waitingForLock": false,
"progress": {},
"msg": ""
}
],
"ok": 1
}
默认启用大型索引键
即使文档不包含具有大量字符的键或文档不包含多层嵌套,指定大型索引键也能确保涵盖这些场景。
请考虑在“cosmicworks”数据库的“large_index_coll”集合上启用大型索引键这个示例。
use cosmicworks;
db.runCommand(
{
"createIndexes": "large_index_coll",
"indexes": [
{
"key": { "ikey": 1 },
"name": "ikey_1",
"enableLargeIndexKeys": true
}
]
})
使用阻止选项将使索引生成优先于新的写入操作
对于在加载数据之前应创建索引的场景,应使用阻止选项来阻止传入的写入,直到索引生成完成。
设置 { "blocking": true }
特别适合在数据写入开始前在空集合上创建索引的迁移实用工具。
请考虑在“cosmicworks”数据库的“employee”集合上创建索引的有关阻止选项的示例:
use cosmicworks;
db.runCommand({
createIndexes: "employee",
indexes: [{"key":{"name":1}, "name":"name_1"}],
blocking: true
})
相关内容
查看文本索引,它有助于实现高效搜索和对基于文本的数据的查询。