Docs 菜单
Docs 主页
/
MongoDB Manual
/

已填充集合上的索引构建

在此页面上

  • 行为
  • 构建索引对数据库性能的影响
  • 复制环境中的索引构建
  • 构建失败与恢复
  • 监控进行中的索引构建
  • 终止正在进行的索引构建
  • 索引构建过程

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

索引构建在副本集或分片集群上,并在所有数据承载副本集成员上同时构建。主节点要求最少数量的数据承载有投票权的节点(即提交法定人数),包括其本身,必须先完成构建,然后才能将索引标记为可供使用。“有投票权的”节点是 members[n].votes 大于 0 的任何副本集节点。有关更多信息,请参阅复制环境中的索引构建

MongoDB 的早期版本支持在前台或后台构建索引。在前台构建索引速度快,可生成更高效的索引数据结构。但是,在为集合构建索引期间,需要阻止对其父数据库的所有读写访问。在后台构建索引速度较慢,其生成的索引数据结构也不如前台构建的高效,但允许在构建过程中对数据库及其集合进行读写访问。

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

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

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

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

对于对集合实施约束的索引(例如唯一索引), mongod会在索引构建完成检查所有预先存在的和同时写入的文档是否违反这些约束。违反索引约束的文档可能会在索引构建期间存在。如果在构建结束时有任何文档违反了索引约束,则mongod会终止构建并抛出错误。

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

同样,正在进行索引构建时,应用程序可以成功地将具有product_sku重复值的文档成功写入inventory集合。如果在构建结束时仍然存在任何违规行为, mongod将终止构建并抛出错误。

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

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

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

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

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

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

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

提示

另请参阅:

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

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

在目标集合处于大量写入负载的时间段内构建索引,可能会导致写入性能降低,且索引构建的时间将更长。

请考虑指定一个维护窗口,在此期间应用程序将停止或减少针对集合的写入操作。应在此维护窗口内启动索引构建,以降低构建过程中潜在的负面影响。

createIndexes支持在集合上构建一个或多个索引。 createIndexes使用内存和磁盘上的临时文件的组合来完成索引构建。 createIndexes的默认内存使用限制为200 MB,在使用单个createIndexes命令构建的所有索引之间共享。达到内存限制后, createIndexes会使用--dbpath目录中名为_tmp的子目录中的临时磁盘文件来完成构建。

您可以通过设置 maxIndexBuildMemoryUsageMegabytes 服务器参数来覆盖内存限制。设置更高的内存限制可能会加快完成索引构建过程。但是,相对于系统上未使用的 RAM 而言,将此限制设置得太高可能会导致内存耗尽和服务器关闭。

如果主机的可用空闲 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 命令。

注意

索引构建可能会影响副本集性能。对于无法容忍因索引构建而导致性能下降的工作负载,请考虑进行滚动索引构建。滚动索引构建一次最多选取一个副本集节点(始于从节点),使其暂时作为独立运行的实例进行索引构建。滚动索引构建需要进行至少一次副本集选举。

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

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

  • 写入操作使用写关注

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

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

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

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

从 MongoDB5 0mongodshutdown"force" : trueSIGTERMvotingMembers开始。 ,如果主节点 使用 执行干净的 } 或在索引构建期间接收 信号,并且 commitQuorum 设置为默认值 ,则会保存索引构建进度到磁盘。mongod 重新启动时会自动恢复索引构建,并从保存的检查点继续运行。在早期版本中,如果索引构建中断,则必须从头开始。

从 MongoDB5 0mongodshutdown"force" : trueSIGTERMvotingMembers开始。 ,如果从节点 使用 执行干净的 } 或在索引构建期间接收 信号,并且 commitQuorum 设置为默认值 ,则会保存索引构建进度到磁盘。mongod 重新启动时会自动恢复索引构建,并从保存的检查点继续运行。在早期版本中,如果索引构建中断,则必须从头开始。

mongod可以在构建恢复索引时执行启动过程。

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

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

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

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

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

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

如果一个分片集合在包含集合数据块的每个分片上没有完全相同的索引(包括索引选项),则该集合的索引不一致。尽管一般操作过程中不应出现索引不一致的情况,但这种情况仍有可能发生,例如:

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

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

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

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

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锁。

提示

← 将现有索引转换为唯一索引