Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs 菜单
Docs 主页
/ /

已填充集合上的索引构建

索引构建使用优化的构建进程,该进程在索引构建的开始和结束时在集合上持有独占锁。构建进程的其余部分交叉执行读取和写入操作。有关索引构建进程和锁定行为的详细说明,请参阅 索引构建进程。

索引构建在副本集或分片集群上,同时在所有承载数据的副本集节点上构建。主节点 (primary nodemembers[n].votes 0in the replica set)需要最少数量的承载数据的投票成员(即提交法定人数),包括其自身,这些成员必须在将索引为可供使用之前完成构建。 “有投票权的”节点是 大于 的任何副本集节点。有关更多信息,请参阅复制环境中的索引构建。

注意

有关在 Atlas 中创建索引的信息,请参阅 Atlas 文档中的索引管理页面。

上一个版本的MongoDB支持在前台或背景构建索引。前台索引构建速度快,可生成更高效的索引数据结构,但需要在构建期间阻止对正在编制索引的集合的父数据库进行所有读写访问权限。后台索引构建速度较慢,产生的结果效率较低,但允许在构建期间对数据库及其集合进行读写访问权限。

索引构建现在仅在构建开始和结束时获得对正在编制索引的集合的独占锁。构建进程的其余部分使用背景索引构建的让出行为,以在构建最大限度地提高对集合的读写访问访问权限。尽管锁定行为更加宽松,但索引构建仍然会产生高效的索引数据结构。

经优化的索引构建性能至少与后台索引构建相当。如果在构建过程中,工作负载内含有很少或不含更新操作,经优化的索引构建速度可以和对相同数据进行前台索引构建一样快。

使用 db.currentOp() 监控正在进行的索引构建进度。

如果为 createIndexes 或其 shell 助手createIndex()createIndexes() 指定了 background 索引构建选项,则 MongoDB 将忽略此选项。

对于在集合上实施约束的索引,例如唯一索引,mongod 会在索引构建完成后检查所有先前存在和并行写入的文档是否违反了这些约束。在索引生成过程中,可能会存在违反索引约束的文档。如果在构建结束时有任何文档违反了索引约束,mongod 会终止构建并抛出错误。

例如,考虑一个已填充的集合 inventory。管理员希望在 product_sku 字段上创建唯一索引。如果集合中的任何文档具有重复的 product_sku 值,则索引构建仍然可以成功启动。如果在构建结束时仍然存在任何违规行为,mongod 将终止构建并报告错误。

同样,正在进行索引构建时,应用程序可以成功地将具有 product_sku 重复值的文档成功写入inventory集合。

为了降低由于违反约束条件而导致索引构建失败的风险,请执行以下操作:

  • 验证集合中没有违反索引约束的文档。

  • 停止所有可能违反索引约束条件的应用程序对集合的写入操作

对于分布式在多个分片上的分片的集合,一个或多个分片可能包含具有重复文档的数据块。因此,创建索引操作可能在某些分片(即没有重复项的分片)上成功,但在其他分片(即有重复项的分片)上失败。为了避免在分片之间留下不一致的索引,您可以从 发出db.collection.dropIndex() mongos以从集合中删除索引。

为了降低发生这种情况的风险,在创建索引之前请:

  • 验证集合中没有违反索引约束的文档。

  • 停止所有可能违反索引约束条件的应用程序对集合的写入操作

提示

默认情况下,服务器最多允许三个并发索引构建。要更改允许的并发索引构建数,请修改 maxNumActiveUserIndexBuilds 参数。

如果并发索引构建的数量达到 maxNumActiveUserIndexBuilds 指定的限值,服务器将阻止其他索引构建,直到并发索引构建的数量降至限值以下。

在目标集合承受较重写入负载时构建索引可能会导致写入性能降低和索引构建时间更长。

请考虑指定一个维护窗口,在此期间应用程序会停止或减少针对集合的写入操作。在此维护窗口期间启动索引构建。

createIndexes 支持在集合上构建一个或多个索引。createIndexes 使用内存和磁盘上的临时文件的组合来构建索引。默认内存限制为每个createIndexes命令 200 兆字节,由该命令中构建的所有索引平均共享。示例,如果您使用一个createIndexes命令构建10 个索引,则在使用默认内存限制 200 时, MongoDB会为每个索引分配 20 MB 的内存用于索引构建进程。当达到内存限制时, MongoDB会在 --dbpath 内的 _tmp 子目录中创建临时文件以完成构建。

使用 maxIndexBuildMemoryUsageMegabytes 参数调整内存限制。仅在极少数情况下才需要增加此参数,例如当您运行单个createIndexes命令同时运行多个索引构建时,或者对大于 500 GB 的数据集索引时。

每个createIndexes命令的限制为maxIndexBuildMemoryUsageMegabytes。使用默认maxNumActiveUserIndexBuilds 3 时,所有并发索引构建的总内存使用量最多可能达到maxIndexBuildMemoryUsageMegabytes值的 3 倍。

如果主机的可用空闲 RAM 有限,则可能需要安排维护期以增加系统总 RAM,然后才能修改 mongod RAM 的使用量。

注意

需要 featureCompatibilityVersion 4.4+

副本集或分片集群中的每个 mongod 必须featureCompatibilityVersion 设置为至少 4.4,才能跨副本集节点同时启动索引构建。

索引构建在副本集或分片集群上,并在所有数据承载副本集成员上同时构建。对于分片集群,索引构建仅会在包含当前被索引集合的数据的分片上进行。主节点需要最少数量的数据承载 voting 节点(即提交法定节点数),包括其自身,这些节点必须在将索引标记为可供使用之前完成构建。

构建过程总结如下:

  1. 主节点接收 createIndexes 命令并立即创建与索引构建关联的 “startIndexBuild” oplog 条目。

  2. 从节点 (secondary node from replica set) 在复制 “startIndexBuild” oplog 条目后开始索引构建过程。

  3. 每个节点完成为集合中数据构建索引后,将通过“投票”来提交构建的索引。

  4. 从节点会继续处理针对索引的所有新写入操作,同时等待主节点确认投票数量是否达到定额。

  5. 当主节点获得足量的投票时,它会检查任何违反键约束的情况,例如重复键错误。

    • 如果没有违反键约束的情况出现,主节点会完成索引构建,将索引标记为可用,并创建相关的“commitIndexBuild” oplog 条目。

    • 如果出现任何违反键约束的情况,索引构建将失败。主节点将中止索引构建并创建相关的“abortIndexBuild” oplog 条目。

  6. 从节点复制“commitIndexBuild” oplog 条目并完成索引构建。

    如果从节点复制的是“abortIndexBuild” oplog 条目,它们会中止索引构建并放弃构建作业。

对于分片集群环境,在为其中的集合构建索引时,索引构建过程仅在含有该集合数据的分片上发生。

有关索引构建流程的更详细说明,请参阅索引构建流程

默认情况下,索引构建使用 "votingMembers" 的提交法定人数,或所有数据承载投票成员。要使用非默认提交法定人数启动索引构建,请将 commitQuorum 参数指定为 createIndexes 或其 shell 助手 db.collection.createIndex()db.collection.createIndexes()

要修改正在进行的同步索引构建所需的提交法定人数,请使用 setIndexCommitQuorum 命令。

警告

避免同时执行滚动索引和复制索引构建过程,因为这可能会导致意外问题,例如构建中断和循环崩溃。

注意

滚动索引构建一次最多使用一个副本集成员(从从节点(secondary node from replica set)开始),并在该成员上构建索引作为独立运行的。滚动索引构建至少需要一次副本集选举。仅当满足滚动索引页面上列出的要求时才使用滚动索引构建,因为该过程会降低集群的弹性。

提交法定人数写关注之间有重要区别:

  • 索引构建使用提交法定人数

  • 写入操作使用写关注

集群中的每个承载数据的节点均为一个有投票权成员。

提交法定人数指定了必须准备多少个承载数据的有投票权节点,或是哪些有投票权节点(包括主节点)来提交同步索引构建。主节点才会执行提交。

写关注是指确认写入操作已传播到指定数量的实例的级别。

提交法定人数指定了在主节点提交索引构建之前必须有多少个节点准备好完成索引构建。相反,当主节点已提交索引构建时,写关注则指定了在此命令返回之前有多少个节点必须完成索引构建。

如果主节点 (primarymongod shutdown"force" : trueSIGTERMnode votingMembersinmongod the replica set)或从节点(secondary node from replica set) 使用 执行干净的 或在索引构建期间收到 信号,并且 commitQuorum设立为默认 ,则会将索引构建进度保存到磁盘。 会在重新启动时自动恢复索引构建,并从保存的检查点继续运行。在早期版本中,索引构建必须从头开始。

mongod 可以在恢复索引构建时执行初创企业进程。

如果您将mongod 作为独立运行运行重新启动(即,删除或注释掉replication.replSetName 或省略--replSetName ),则mongod 将无法重新启动索引构建。构建保持暂停状态,直到手动执行dropped

如果 mongod 在索引构建期间关闭,则索引构建作业和所有进度都将丢失。重新启动 mongod 不会重新启动索引构建。必须重新执行 createIndex() 操作,才能重新启动索引构建过程。

从 MongoDB 5.0 开始,如果在索引构建期间某一节点回滚到之前的状态,则会将索引构建进度保存到磁盘。如果回滚结束时仍有工作要做,mongod 则会自动恢复索引构建,并从保存的检查点继续运行。

MongoDB 可以暂停正在进行的索引构建,以执行回滚

  • 如果回滚没有撤销索引构建进度,MongoDB 会在完成回滚后重新启动索引构建作业。

  • 如果回滚操作撤销了索引构建进度,您必须在回滚完成后重新创建一个或多个索引。

如果分片的集合在包含集合数据段的每个分片上不具有完全相同的索引(包括索引选项),则该集合存在不一致索引。虽然在正常操作期间不应出现索引不一致,但在以下情况下可能会出现索引不一致:

  • 创建具有 unique 键约束的索引,并且一个分片包含具有重复文档的数据数据块时。在这种情况下,创建索引操作可能在没有重复项的分片上成功,但在有重复项的分片上失败。

  • 以滚动方式跨分片创建索引(即手动跨分片逐个构建索引),但无法为关联的分片构建索引,或者错误地构建了不同规格的索引。

配置服务器主节点会定期检查分片集合的分片之间的索引不一致情况。要配置这些定期检查,请参阅 enableShardedIndexConsistencyCheckshardedIndexConsistencyCheckIntervalMS

在配置服务器主节点上运行时,命令 serverStatus 返回字段 shardedIndexConsistency 以报告索引不一致的情况。

要检查分片集合是否存在不一致的索引,请参阅查找分片间不一致的索引

要查看索引构建操作的状态,可以使用 mongosh 中的 db.currentOp() 方法。要过滤索引创建操作的当前操作,请参阅主动创建索引的操作,查看相关示例。

msg 字段包括了索引构建过程中当前阶段的完成百分比测量值。

构建索引时,进度会写入 MongoDB 日志。如果索引构建已停止并恢复,则会出现包含如下字段的日志消息:

"msg":"Index build: wrote resumable state to disk",
"msg":"Found index from unfinished build",

使用 dropIndexes 命令或其 Shell 助手 dropIndex()dropIndexes() 来终止正在进行的索引构建。有关更多信息,请参阅停止正在进行的索引构建

使用 killOp 终止副本集或分片集群中正在进行的索引构建。

下表描述了索引构建过程中的每个阶段:

阶段
说明

mongod 会获得对正在编入索引的集合的独占 X 锁。这会阻塞集合上的所有读取和写入操作,包括应用任何复制的写入操作或针对集合的元数据命令。mongod 不会产生此锁。

初始化

mongod 在此初始状态下创建了以下三个数据结构:

  • 初始索引元数据条目。

  • 一张临时表(“侧写表”),用于存储在构建过程中,对被索引的集合进行写入时生成的键。

  • 临时表(“约束违规表”),用于显示可能导致密钥生成错误的所有文档。当文档的索引字段具有无效键时,会发生键生成错误。例如,在构建唯一索引时出现重复字段值的文档,在构建 2dsphere 索引时出现格式错误的 GeoJSON 对象

mongod 将独占 X 集合锁降级为意向独占 IX 锁。mongod 会定期生成此锁以交替执行读取和写入操作。

扫描集合

对于集合中的每个文档,mongod 会为该文档生成密钥并将密钥转储到外部排序器中。

如果 mongod 在集合扫描期间生成密钥时遇到密钥生成错误,则会将密钥存储在约束违规表中以供日后处理。

如果 mongod 在生成键时遇到任何其他错误,则构建过程会失败并显示错误。

一旦 mongod 完成集合扫描,它就会将排序后的键转储到索引中。

处理侧写入表

mongod 使用先入先出的优先级顺序清空侧写入表。

如果 mongod 在处理旁写表中的键时出现键生成错误,则会将该密钥存储在约束违规表中以供日后处理。

如果 mongod 在处理键时遇到任何其他错误,则构建过程将失败并显示错误。

对于在构建过程中写入集合的每个文档,mongod 会为该文档生成一个密钥并将其存储在侧写入表中以供日后处理。mongod 使用快照系统来设置要处理的密钥数量的限制。

投票并等待提交法定人数

属于副本集的 mongod 会跳过此阶段。

mongod 向主节点提交“投票”来提交索引。具体来说,它将“投票”写入主节点上的内部复制集合。

如果 mongod主节点,它会等到达到投票提交法定人数(默认情况下所有投票数据承载成员),然后再继续索引构建进程。

如果 mongod从节点,它将一直等到复制“commitIndexBuild”或“abortIndexBuild”oplog 条目为止:

  • 如果 mongod 复制“commitIndexBuild”oplog 条目,它会排空侧写入表,并进入索引构建过程的下一阶段。

  • 如果 mongod 复制“abortIndexBuild”oplog 条目,它将中止索引构建并放弃构建作业。

在等待提交法定人数时,mongod 会将写入到正在构建索引的集合的操作生成的所有附加键添加到侧写入表,并定期清空该表。

mongod 将集合上的意向独占 IX 锁升级为共享 S 锁。这会阻塞针对集合的所有写入操作,包括应用任何复制的写入操作或针对集合的元数据命令。

完成处理临时侧写入表

mongod 继续清空侧写入表中的剩余记录。在此阶段,mongod 可能会暂停复制。

如果 mongod 在处理旁写表中的键时出现键生成错误,则会将该密钥存储在约束违规表中以供日后处理。

如果 mongod 在处理键时遇到任何其他错误,则构建过程将失败并显示错误。

mongod 将集合上的共享 S 锁升级为集合上的独占 X 锁。这会阻塞集合上的所有读取和写入操作,包括应用任何复制的写入操作或针对集合的元数据命令。mongod 不会生成此锁。

删除侧写入表

mongod 在删除侧写入表之前应用该表中的所有剩余操作。

如果 mongod 在处理旁写表中的键时出现键生成错误,则会将该密钥存储在约束违规表中以供日后处理。

如果 mongod 在处理键时遇到任何其他错误,则构建过程将失败并显示错误。

此时,索引包括写入集合的所有数据。

进程约束违规表

如果 mongod主节点,则会按照先入先出的优先级顺序清空约束违规表。

  • 如果约束违规表中没有键产生键生成错误该表为空,则 mongod 会删除该表并创建 "commitIndexBuild" oplog 条目。从节点可以在复制 oplog 条目后完成关联的索引构建。

  • 如果约束违规表中有某个键仍会产生键生成错误,则 mongod 将中止构建并报告错误。mongod 创建关联的 "abortIndexBuild" oplog 条目,指示从节点应中止并放弃索引构建作业。

如果 mongod从节点,则会删除约束违规表。由于主节点必须在创建 "commitOplogEntry" oplog 条目之前成功清空约束违规表,因此从节点可以安全地假设不存在违规。

将索引标记为可供使用

mongod 会更新索引元数据以将索引标记为可供使用。

mongod 将释放集合上的 X 锁。

后退

分片集合

在此页面上