MongoDBのインデックスについて

はじめまして、ココネでインフラ・データベースを担当しているYです。

ココネではメインDBとしてMariaDBとMongoDBを使っていますが、今回はMongoDBのインデックスについてお話しできればと思います。

 

MongoDBのインデックスはRDBのB-Treeインデックスと似ていますので、それをベースにいくつかのTipsをご紹介します。

インデックスの管理コスト

クエリのパフォーマンスを高めるためにコレクションにインデックスを追加しますが、インデックスは維持するのに管理コストがかかるものです。

コレクションにデータを登録するコストを1とすると、インデックスキーを追加するコストは一般的に1〜1.5くらいだと予想されます。

例えばインデックスが3つあるコレクションにデータを登録すると、そのコストは約5.5(1 + 1.5 * 3)くらいになります。

インデックスの数が増えれば増えるほどデータ登録時のコストがかかり、データ更新・削除の時もインデックスキーの更新が発生するので、さらに管理コストがかかります。

インデックスの合計サイズ

またクエリのパフォーマンスを高めるためには、インデックスの参照がディスクから行われないようにメモリ上に存在する必要があります。

 

MongoDBのWiredTigerエンジンでは物理メモリの50%をOSのファイルシステムキャッシュとして、残りの50%はWiredTigerキャッシュとして割り当てます。

このWiredTigerキャッシュの使用率が80%を超えると使用頻度が低いワーキングセット(最も頻繁にアクセスするデータの一部分)とインデックスなどをキャッシュから開放する処理が活性化され、ディスクIOが頻繁に発生するようになります。

そのためインデックスの合計サイズはWiredTigerキャッシュの80%を超えないように管理する必要があります。

実際はWiredTigerキャッシュにはインデックスのほかにワーキングセットも乗るので、もう少し余裕を持った方が良いと思います。

上記の理由から不要なインデックス(重複、使用頻度が低いもの)は消し、必要最低限の数だけ維持しましょう。

MongoDBのインデックスのTips

1つのクエリで使われるインデックスは基本1つ

例外としてOR条件と、1つのクエリで2つのインデックスを使う「Index Intersection」がありますが、実際は効率が悪くOptimizerからあまり選ばれないプランになります。
そのため単一インデックスを複数作成するより複合インデックスを作成するほうが良いでしょう。
https://www.mongodb.com/docs/manual/core/index-intersection/

ESR(Equality, Sort, Range)のルール

複合インデックスの作成時のインデックスキー配置の優先順位はESR(Equality, Sort, Range) の順です。
よく間違えるのはクエリの条件にあるフィールドをソートのフィールドより前に置くことです。
この場合、条件にRange検索があるとソートにインデックスが利用できず、メモリまたはディスクを利用するソートになります。
複合インデックスのキーはこのルールに沿って配置しましょう。
https://www.mongodb.com/docs/manual/tutorial/equality-sort-range-rule/

Partial Index

一定条件を満たすデータのみでインデックスを作成することができます。
インデックスのサイズと管理コストの節減ができるので活用しましょう。
https://www.mongodb.com/docs/manual/core/index-partial/

TTL Index

コレクションの肥大化を防ぐいくつかの方法があります。TTLインデックスはその1つです。
設定した有効期間が過ぎたらデータを自動で削除してくれますが、一つ注意点があります。
例えば、ログインボーナスなど毎日の0時にクエストがリセットされる場合、0時を基準にクエストのデータが大量に発生するとします。
このコレクションのTTLインデックスの有効期限を30日に設定します。
そうするとデータは登録した30日後に削除されますが、0時に登録されたデータは30日後の0時に削除されます。
このコレクションに対して大量のデータ登録処理が行われる時に削除も同時に走り、負荷が倍増することになりますので、なるべく登録と削除処理が被らないように有効期限を調整しましょう。
https://www.mongodb.com/docs/manual/core/index-ttl/

 

①TTLインデックスの有効期間を「n日」に設定した場合


②TTLインデックスの有効期間を「n日+3時間」に設定した場合

Hidden Index(バージョン4.4以降)

既存のインデックスが不要となり削除することになっても、本番環境では削除後にどんな影響が発生するか分からない時があります。
もし削除後に実は必要なものだったことが分かったら、またインデックスを作成する必要があります。
このような場合はインデックスを物理的に削除するのではなく、インデックスがOptimizerから選ばれないように隠し設定することができます。
インデックスの削除が不安な時にはこのオプションも考慮しましょう。
https://www.mongodb.com/docs/manual/core/index-hidden/

終わりに

今回はMongoDBのインデックスについて管理ポイントと利用時のTipsをご紹介しました。

MongoDBを運用する上でメモリの管理は大事だと思いますが、そのメモリに直結するインデックスを無駄なく、高いパフォーマンスで使えるためにこの記事が‎ご参考になれば幸いです。

 


 

ココネでは一緒に働く仲間を募集中です。

ご興味のある方は、ぜひこちらの採用特設サイトをご覧ください。

https://www.cocone.co.jp/recruit/contents/

Category

Tag

%d人のブロガーが「いいね」をつけました。