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