データが存在するコレクションでのインデックス構築
項目一覧
インデックス構築では、最適化された構築プロセスを使用し、インデックス構築の開始時と終了時にコレクションを排他ロックします。構築プロセスの残りの部分は、読み取り操作と書き込み (write) 操作のインターリーブによって一時停止されます。インデックス構築プロセスとロック動作の詳細については、 「インデックス構築プロセス」を参照してください。
レプリカセットまたはシャーディングされたクラスター上のインデックスは、データを保持する全レプリカセット ノードで同時に構築されます。プライマリでは、最小数のデータを保持する投票ノード(コミットクォーラム)が必要です。これにはプライマリ自身も含まれます。また、インデックスが使用可能とマークされる前に構築を完了する必要があります。「投票」ノードとは、members[n].votes
が 0
より大きいレプリカセットのノードです。詳細については、 「レプリケートされた環境でのインデックス構築」を参照してください。
注意
Atlas でのインデックス作成の詳細については、Atlas ドキュメントの「インデックス管理ページ 」を参照してください。
動作
フォアグラウンド構築とバックグラウンド構築との比較
MongoDB の以前のバージョンでは、フォアグラウンドまたはバックグラウンドでのインデックスの構築がサポートされていました。フォアグラウンドでのインデックス構築は高速で、より効率の高いインデックスデータ構造が生成されていましたが、構築中はインデックスされるコレクションの親データベースへの読取りおよび書込みアクセスをすべてブロックする必要がありました。バックグラウンドでのインデックス構築は遅く、結果の効率も低いものでしたが、構築プロセス中にデータベースとそのコレクションへの読取りおよび書込みアクセスが可能でした。
インデックス構築では、メタデータの変更を保護するために、構築プロセスの開始時と終了時に、インデックスが作成されるコレクションのみが排他ロックされるようになりました。構築プロセスの残りの部分では、バックグラウンド インデックス構築の一時停止動作を使用して、構築中のコレクションへの読み取り/書込みアクセスを最大化しています。インデックス構築では、ロック動作の制限が緩いにもかかわらず、効率的なインデックス データ構造が生成されます。
最適化されたインデックス構築のパフォーマンスは、最低でもバックグラウンド インデックス構築と同等です。構築プロセス中に更新がほとんどまたはまったく受信されないワークロードの場合、最適化されたインデックス構築は、同じデータに対するフォアグラウンド インデックス構築と同じくらい高速になります。
進行中のインデックス構築の進行状況を監視するには、db.currentOp()
を使用します。
MongoDB では、createIndexes
またはそのシェルヘルパーcreateIndex()
createIndexes()
に指定されている場合は background
インデックス構築は無視されます。
インデックス構築中の制約違反
一意のインデックスなど、コレクションに制約を強制するインデックスの場合、 mongod
はインデックスのビルド完了後に、既存のドキュメントと同時に書込まれたすべてのドキュメントをチェックし、それらの制約に違反しているかどうかをチェックします。 インデックス制約に違反するドキュメントは、インデックスのビルド中に存在する可能性があります。 ビルドの最後にインデックス制約に違反するドキュメントがある場合、 mongod
はビルドを終了し、エラーをスローします。
たとえば、データが入ったコレクションinventory
を考えてみましょう。 管理者が、 product_sku
フィールドに一意のインデックスを作成したいと考えています。 コレクション内のいずれかのドキュメントでproduct_sku
の値が重複している場合でも、インデックスのビルドは正常に開始できます。 ビルドの最後に違反がまだ存在する場合、 mongod
はビルドを終了し、エラーをスローします。
同様に、インデックスのビルドが進行中に、アプリケーションはproduct_sku
の重複する値を持つドキュメントをinventory
コレクションに正常に書き込むことができます。 ビルドの最後に違反がまだ存在する場合、 mongod
はビルドを終了し、エラーをスローします。
制約違反によるインデックス構築失敗のリスクを軽減するには、以下の対策を取ります。
コレクション内のドキュメントがどれもインデックス制約に違反していないことを検証します。
違反のない書き込み操作を保証できないアプリケーションからの、コレクションへの書き込みをすべて停止します。
シャーディングされたコレクション
複数のシャードに分散されたシャーディングされたコレクションの場合、1 つ以上のシャードに重複したドキュメントを含むチャンクが含まれる場合があります。そのため、インデックスの作成操作は、一部のシャード(重複のないシャード)では成功するものの、他のシャード(重複のあるシャード)では成功しない場合があります。シャード間で不整合なインデックスが残らないようにするには、mongos
から db.collection.dropIndex()
を発行して、コレクションからインデックスを削除します。
この問題が発生するリスクを軽減するには、インデックスを作成する前に次の手順を実行します。
コレクション内のドキュメントがどれもインデックス制約に違反していないことを検証します。
違反のない書き込み操作を保証できないアプリケーションからの、コレクションへの書き込みをすべて停止します。
最大同時インデックス構築数
デフォルトでは、サーバーは最大 3 つの同時インデックス構築を許可します。許可される同時インデックス構築の数を変更するには、 maxNumActiveUserIndexBuilds
パラメータを変更します。
同時インデックス構築数が maxNumActiveUserIndexBuilds
で指定された制限に達した場合、同時インデックス構築数が制限を下回るまで、サーバーは追加のインデックス構築をブロックします。
インデックス構築がデータベースのパフォーマンスに与える影響
書き込み負荷の高いワークロード中のインデックス構築
ターゲットとなるコレクションの書き込み負荷が大きい時間帯にインデックスを構築すると、書き込みパフォーマンスが低下し、インデックス構築に時間がかかる可能性があります。
アプリケーションがコレクションに対する書き込み操作を停止または削減するメンテナンスウィンドウを指定することを検討してください。このメンテナンスウィンドウ中にインデックス構築を開始することで、構築プロセスの潜在的な負の影響を軽減します。
使用可能なシステムメモリ (RAM) の不足
createIndexes
は、コレクションに 1 つ以上のインデックスの構築をサポートしています。 createIndexes
はメモリとディスク上の一時ファイルの組み合わせを使用してインデックス構築を完了します。 createIndexes
のメモリ使用量のデフォルト制限は200メガバイトで、単一のcreateIndexes
コマンドを使用してビルドされたすべてのインデックスに共有されます。 メモリ制限に達すると、 createIndexes
は--dbpath
ディレクトリ内の_tmp
という名前のサブディレクトリにある一時ディスク ファイルを使用してビルドを完了します。
maxIndexBuildMemoryUsageMegabytes
サーバー パラメータを設定することで、メモリ制限を上書きできます。メモリ制限を高く設定すると、より早くインデックス構築を完了できる可能性があります。ただし、システム上の未使用 RAM に対してこの制限を高く設定しすぎると、メモリが不足し、サーバーがシャットダウンする可能性があります。
ホストマシンで使用可能な空き RAM が限られている場合は、 mongod
RAM 使用量を変更する前に、メンテナンス期間をスケジュールしてシステム RAM の合計を増やす必要がある場合があります。
複製された環境でのインデックス構築
注意
FeatureCompatibilityVersion 4.4 以上が必要です。
レプリカセット全体でインデックス構築を同時に開始するには、レプリカセットまたはシャーディングされたクラスター内の各 mongod
は、featureCompatibilityVersion を少なくとも 4.4
に設定する必要があります。
レプリカセットまたはシャーディングされたクラスター上のインデックスは、データを保持するすべてのレプリカセット ノードで同時に構築されます。シャーディングされたクラスターの場合、インデックス構築は、インデックスが作成されるコレクションのデータを含むシャードでのみ行われます。プライマリは、インデックスを使用可能とマークする前に、自身を含む最小限のデータを保持する voting
ノード(コミットクォーラム)でインデックス構築を完了する必要があります。
ビルド プロセスの概要は以下の通りです。
プライマリは、
createIndexes
コマンドを受信し、インデックス構築に関連付けられた "startIndexBuild" oplog エントリを直ちに作成します。セカンダリは、「startIndexBuild」oplog エントリを複製した後、インデックスの構築を開始します。
コレクション内のデータのインデックス作成が終了したら、各ノード間でビルドへのコミットについての ”投票” が行われます。
セカンダリノードは、プライマリが投票の定足数を確認するまで、引き続きインデックスへの新しい書込み操作を処理します。
プライマリで投票の定足数に達すると、重複キーエラーなどキーに関する制約違反がないかどうかがチェックされます。
キー制約違反がない場合、プライマリはインデックス構築を完了し、インデックスを使用準備完了としてマークし、関連する「commitIndexBuild」oplog エントリを作成します。
キー制約違反がある場合、インデックス構築は失敗します。プライマリはインデックス構築を中止し、関連する「abortIndexBuild」oplog エントリを作成します。
セカンダリは「commitIndexBuild」oplog エントリを複製し、インデックス構築を完了します。
セカンダリが代わりに「abortIndexBuild」oplog エントリを複製すると、インデックス構築を中止し、構築ジョブを破棄します。
シャーディングされたクラスターの場合、インデックス構築は、インデックスされるコレクションのデータを含むシャードでのみ行われます。
インデックス構築プロセスの詳細については、「 インデックス構築プロセス 」を参照してください。
デフォルトでは、インデックス構築は "votingMembers"
のコミットクォーラム、つまりすべてのデータを保持する投票ノードを使用します。デフォルト以外のコミット クォーラムでインデックス構築を開始するには、 commitQuorumパラメータをcreateIndexes
またはそのシェルヘルパー db.collection.createIndex()
および db.collection.createIndexes()
に指定します。
進行中の同時インデックス構築に必要なコミットクォーラムを変更するには、setIndexCommitQuorum
コマンドを使用します。
注意
インデックス構築はレプリカセットのパフォーマンスに影響を与える可能性があります。インデックス構築によるパフォーマンスの低下を許容できないワークロードの場合は、ローリングインデックス構築プロセスの実行を検討してください。ローリングインデックス構築では、一度に最大 1 つのレプリカセットノードを使用し、セカンダリノードから始めて、そのノードにスタンドアロンとしてインデックスを構築します。ローリングインデックス構築には、少なくとも 1 回のレプリカセット選挙が必要です。
レプリカセットのインデックス構築については、「レプリカセットのインデックス構築」を参照してください。
シャーディングされたクラスターでのインデックス構築については、「シャーディングされたクラスターでのインデックス構築」を参照してください。
コミットクォーラムと書込み保証の対比
インデックス構築にはコミットクォーラムを使用します。
書き込み操作には書込み保証が必要です。
クラスタ内の各データ保有ノードは投票ノードです。
コミットクォーラムでは、データを保持する投票ノードの数、またはプライマリがコミットを実行する前にプライマリを含めてどの投票ノードが同時インデックス ビルドのコミット準備をしておく必要があるかを指定します。
書込み保証 (write concern) とは、指定された数のインスタンスに書込み (write) が伝わったことを確認するレベルです。
コミットクォーラムでは、プライマリがインデックス構築にコミットする前に、インデックス構築を完了する準備が整っていなければならないノードの数を指定します。対照的に、プライマリがインデックス構築にコミットした時に、書込み保証によって、コマンドが返されるまでにインデックス構築を完了する必要があるノードの数が指定されます。
構築の失敗と復元
プライマリで中断されたインデックス構築 mongod
MongoDB 5.0以降では、プライマリmongod
が"force" : true
を使用してクリーンなshutdown
を実行するか、インデックス構築中にSIGTERM
シグナルを受信し、 commitQuorumがデフォルトのvotingMembers
に設定されている場合、インデックス構築進行状況はディスクに保存されます。 mongod
は再起動時に自動的にインデックス構築を回復し、保存されたチェックポイントから続行します。 以前のバージョンでは、インデックスの構築が中断された場合、最初からやり直す必要がありました。
セカンダリで中断されたインデックス構築 mongod
MongoDB 5.0以降では、セカンダリ mongod
が "force" : true
を使用してクリーン shutdown
を実行するか、インデックス構築中に SIGTERM
シグナルを受信し、commitQuorum がデフォルトの votingMembers
に設定されている場合、インデックス構築の進行状況がディスクに保存されます。mongod
は、再起動時にインデックス構築を自動的に回復し、保存されたチェックポイントから続行します。以前のバージョンでは、インデックス構築が中断された場合、最初からやり直す必要がありました。
mongod
は、リカバリ インデックスの構築中にスタートアッププロセスを実行できます。
mongod
をスタンドアロン( replication.replSetName
を削除またはコメントアウトするか、 --replSetName
を省略すると、 mongod
はインデックスビルドを再開できなくなります。 手動でdropped
になるまで、ビルドは一時停止状態のままになります。
スタンドアロンで中断されたインデックス構築 mongod
インデックスビルド中にmongod
がシャットダウンすると、インデックスビルドジョブとすべての進行状況が失われます。 mongod
を再起動しても、インデックスビルドは再開されません。 インデックスのビルドを再開するには、 createIndex()
操作を再発行する必要があります。
ビルドプロセス中のロールバック
MongoDB 5.0以降では、インデックスビルド中にノードが以前の状態にロールバックされた場合、インデックスビルドの進行状況がディスクに保存されます。 ロールバックが完了したときに実行する作業がまだある場合、 mongod
は自動的にインデックス構築を回復し、保存されたチェックポイントから続行します。
MongoDB では、進行中のインデックス構築を一時停止してロールバックを実行できます。
ロールバックしてもインデックス構築が取り消されない場合、MongoDB はロールバック完了後にインデックス構築を再開します。
ロールバックによってインデックス構築が取り消された場合は、ロールバックの完了後に 1 つまたは複数のインデックスを再作成する必要があります。
シャーディングされたコレクションのインデックスの整合性チェック
コレクションのチャンクを含む各シャードにまったく同じインデックス(インデックスオプションを含む)がない場合、シャーディングされたコレクションのインデックスには一貫性がありません。通常の操作では一貫性のないインデックスは発生しないはずですが、次のような一貫性のないインデックスが発生する可能性があります。
ユーザーが
unique
キー制約を使用してインデックスを作成していて、1 つのシャードに重複ドキュメントを含むチャンクが含まれている場合。このような場合、インデックスの作成操作は、重複のないシャードでは成功するものの、重複のあるシャードでは成功しない可能性があります。ユーザーが複数のシャードにわたってインデックスをローリング処理で作成している(複数のシャードにわたって手作業でインデックスを 1 つずつ構築している)時、関連付けられたシャードのインデックス作成に失敗した場合、または異なる仕様で誤ったインデックスを構築した場合。
コンフィギュレーションサーバーのプライマリは、シャーディングされたコレクションのシャード間でのインデックスの不整合を定期的にチェックします。 これらの定期的チェックを構成するには、 enableShardedIndexConsistencyCheck
とshardedIndexConsistencyCheckIntervalMS
を参照してください。
コマンドserverStatus
は、構成サーバーのプライマリで実行された場合にインデックスの不整合を報告するフィールド shardedIndexConsistency
を返します。
シャーディングされたコレクションに一貫性のないインデックスがないかどうかを確認するには、「シャード間で一貫性のないインデックスを検索する」を参照してください。
進行中のインデックス構築の監視
インデックス構築操作のステータスを確認するには、 のdb.currentOp()
mongosh
メソッドを使用できます。インデックス作成操作の現在の操作をフィルタリングする方法の例については、「アクティブなインデックス作成操作 」を参照してください。
msg
フィールドには、インデックス構築プロセスの現在のステージにおける完了割合が含まれています。
インデックス構築の停止と再開をログで確認
インデックスが構築されている間、進捗状況は MongoDB ログに記録されます。インデックス構築が停止して再開されると、次のようなフィールドを含むログメッセージが表示されます。
"msg":"Index build: wrote resumable state to disk", "msg":"Found index from unfinished build",
進行中のインデックス構築の終了
進行中のインデックス構築を終了するには、 dropIndexes
コマンドまたはそのシェルヘルパー dropIndex()
または dropIndexes()
を使用します。詳細については、「進行中のインデックス構築の停止」を参照してください。
レプリカセットまたはシャーディングされたクラスターで進行中のインデックス構築を終了するためにkillOp
は使用しないでください。
インデックス構築のプロセス
次の表は、インデックス構築プロセスの各段階について説明しています。
ステージ | 説明 |
---|---|
ロック |
|
初期化 |
|
ロック |
|
コレクションのスキャン | コレクション内の各ドキュメントに対して、 コレクションスキャン中に
|
プロセスサイド書込みテーブル |
|
投票とコミットクォーラムの待機 | レプリカセットの一部ではない
コミットクォーラムを待っている間、 |
ロック |
|
一時サイド書き込みテーブルの処理の完了 |
|
ロック |
|
サイド書き込みテーブルの削除 |
この時点で、インデックスにはコレクションに書き込まれたすべてのデータが含まれます。 |
プロセス制約違反テーブル |
|
インデックスを準備完了としてマークします |
|
ロック |
|