しばらくの間、MongoDBを使用していて、今日、同僚と話し合っているときに疑問がありました。
問題は、MongoDBでインデックスを作成すると、コレクションが処理され、インデックスが構築されることです。
ドキュメントの挿入と削除の間にインデックスが更新されるので、インデックスの再構築操作(インデックスを削除してから再構築する)を実行する必要が本当にありません。
MongoDBのドキュメントによると:
通常、MongoDBは定期的な更新中にインデックスを圧縮します。ほとんどのユーザーにとって、reIndexコマンドは不要です。ただし、コレクションのサイズが大幅に変更された場合、またはインデックスが過度のディスク容量を消費している場合は、実行する価値があります。
価値のあるインデックスの再構築操作を実行する必要がありましたか?
MongoDBのドキュメントによれば、通常、定期的にインデックスを再構築する必要はありません。
[〜#〜]注[〜#〜]: pluggableストレージエンジンAPI 。以下の私のコメントは、MongoDB 3.0以前のデフォルトのMMAPストレージエンジンを特に参照しています。 WiredTigerと他のストレージエンジンは、データとインデックスに対して異なるストレージ実装を持っています。
MMAPストレージエンジンを使用してインデックスを再構築すると、次のような利点があります。
インデックスは、データと比較して予想よりも多くの領域を消費しています。注:比較のためのベースラインを取得するには、履歴データとインデックスサイズを監視する必要があります。
古いインデックス形式から新しいインデックス形式に移行したい。再インデックスが表示される場合は、アップグレードノートに記載されています。たとえば、MongoDB 2.0では大幅な インデックスパフォーマンスの向上 が導入されたため、リリースノートには、アップグレード後のv2.0形式への推奨される再インデックスが含まれています。同様に、MongoDB 2.6は 2dsphere
(v2.0)インデックス を導入しました。これは、デフォルトの動作が異なります(デフォルトではスパース)。インデックスバージョンのアップグレード後、既存のインデックスは再構築されません。 if/whenのアップグレードの選択は、データベース管理者に任されています。
コレクションの_id
形式を、単調に増加するキー(ObjectIDなど)に、またはランダムな値に変更しました。これは少し難解ですが、常に増加している_id
sを挿入している場合、Bツリーバケットを90/10(50/50ではなく)に分割するインデックス最適化があります(参照: SERVER-98 )。 _id
sの性質が大幅に変化した場合、再インデックスを使用してより効率的なbツリーを構築できる可能性があります。
一般的なBツリーの動作の詳細については、次を参照してください。 Wikipedia:B-tree
インデックスの内部についてもう少し詳しく知りたい場合は、いくつかの実験的なコマンド/ツールを試してみてください。これらはMongoDB 2.4および2.6のみに限定されると思います。
正確な技術的な理由はわかりませんが、MongoDBでは、他のシステムからのインデックス付けについて知っていることや、引用したドキュメントに基づいて、これについていくつかの仮定を立てることができます。
あるドキュメントから次のドキュメントに移動する場合、完全なドキュメントコレクションでは、処理する必要のないすべてのデータをスキップして、多くの無駄な時間と労力を費やしています。 ID「1234」のドキュメントを探している場合、各ドキュメントを100K以上移動する必要があるため、処理が遅くなります
インデックスを使用すると、コレクション内の各ドキュメントのコンテンツ全体を検索する必要がなく(ディスクの読み取りヘッドを物理的に移動するなど)、インデックスを高速化できます。これは基本的に、ドキュメントのIDと場所を提供するキーと値のペアです。 MongoDBは、インデックス内のすべてのIDをすばやくスキャンし、必要なドキュメントの場所を見つけて、直接ロードすることができます。
インデックスは、基本的にははるかに小さな場所に格納されるキーと値のペアであるため、ディスク領域を占有します。コレクションが非常に大きい場合(コレクション内のアイテム数が多い場合)、インデックスのサイズが大きくなります。
ほとんどのオペレーティングシステムは、特定のブロックサイズでディスク領域のチャンクを割り当てます。ほとんどのデータベースは、必要に応じてディスクスペースを大きなチャンクで割り当てます。
100Kのドキュメントが追加されたときに100Kのファイルサイズを拡大する代わりに、MongoDBはおそらく1MBまたは10MB程度に拡大します-実際の拡大サイズはわかりません。 SQL Serverでは、成長の速さを知ることができ、MongoDBはおそらくそのようなものを持っています。
チャンクで成長すると、データベースを常に拡張する必要がないため、ドキュメントをより迅速にスペースに「成長」させることができます。データベースにすでに10MBのスペースが割り当てられている場合、そのスペースを使い切ることができます。各ドキュメントのファイルを展開し続ける必要はありません。データをファイルに書き込むだけです。
これはおそらく、コレクションとコレクションのインデックス(ディスクに格納されているもの)に当てはまります。
大規模なコレクションに多数のドキュメントが追加および削除されると、インデックスが断片化されます。インデックスを構築する必要があるときに、インデックスファイルの最後ではなく途中にスペースがあったため、インデックスキーが順序どおりではない可能性があります。インデックスキーの間にも、多くのスペースがある場合があります。
インデックスに10,000項目あり、#10,001を挿入する必要がある場合は、インデックスファイルの途中に挿入される可能性があります。今度は、インデックスを再構築して、すべてを元に戻す必要があります。これには、大量のデータを移動して、ファイルの最後にスペースを空け、アイテム#10,001を最後に配置する必要があります。
インデックスが絶えずスラッシングされている場合-多くのものが削除および追加されている場合-インデックスファイルのサイズを大きくし、常に最後に置く方がおそらく高速です。これはインデックスを作成するのに高速ですが、古いものが削除されたファイルに空の穴が残ります。
インデックスファイルに空のスペースがあり、以前は削除されたものがあった場合、これはインデックスを読み取るときに無駄な作業になります。インデックスファイルは、インデックス内の次のアイテムに移動するために、必要以上に移動しています。したがって、インデックスはそれ自体を修復します...これは、非常に大きなコレクションまたはコレクションに対する非常に大きな変更に対しては時間がかかる可能性があります。
インデックスファイルを適切なサイズに適切に圧縮し直すには、すべての順序で、大量のディスクアクセスとI/O操作が必要になる場合があります。場違いなアイテムを一時的な場所に移動し、適切な場所にスペースを空けて、アイテムを元に戻します。ところで、スペースを空けるには、他のアイテムを一時的な場所に移動する必要がありました。再帰的で強引です。
したがって、コレクション内に非常に多数のアイテムがあり、そのコレクションに定期的にアイテムが追加および削除される場合、インデックスを最初から再構築する必要がある場合があります。これを行うと、現在のインデックスファイルがワイプされ、ゼロから再構築されます。これは、既存のファイル内で何千もの移動を行うよりもおそらく高速です。移動するのではなく、最初から順番に書き込むだけです。
上記で想定しているすべてのものを与えると、コレクションのサイズが大きく変化すると、この種のスラッシングが発生します。コレクションに10,000のドキュメントがあり、そのうちの8,000を削除した場合は、まあ、インデックスファイルに8,000のアイテムがあった場所に空のスペースができました。 MongoDBは、残りの2,000アイテムを物理ファイル内で移動して、コンパクトな形式で再構築する必要があります。
8,000の空きスペースがクリーンアップされるのを待つのではなく、残りの2,000のアイテムでゼロから再構築する方が速い場合があります。
したがって、あなたが引用したドキュメントは、おそらく「ビッグデータ」のニーズ、または高スラッシングのコレクションとインデックスを扱うことになるでしょう。
また、索引付け、ディスク割り当て、ファイルの断片化などについて知っていることに基づいて、知識に基づいた推測を行っていることにも留意してください。
私の推測では、ドキュメントの「ほとんどのユーザー」は、99.9%以上のmongodbコレクションがこれについて心配する必要がないことを意味します。
MongoDBのドキュメントによると:
Remove()メソッドはインデックスを削除しません
したがって、コレクションからドキュメントを削除すると、そのコレクションのインデックスを再構築しない限り、ディスク領域が無駄になります。