はじめに
こんにちは。T.H.です。
MongoDBの複合インデックスについて調べる機会がありましたので短めにまとめます。
結論
MongoDBの複合インデックスはB木で作られます。そのため設定時と使用時に順番を強く意識する必要があります。
これにつきます。
複合インデックスの設定
設定方法は以下のような仕様になっています。
db.<collection>.createIndex( {
<field1>: <sortOrder>,
<field2>: <sortOrder>,
...
<fieldN>: <sortOrder>
} )
設定例(java)
//collectionの取得は省略
Document indexKeys = new Document("group", 1)
.append("name", 1);
collection.createIndex(indexKeys, indexOptions);
上記のように設定すると
group - nameの順に昇順でインデックスが作られます。
例えば、以下のデータがあった場合、
group | name |
---|---|
1 | tanaka |
1 | suzuki |
2 | takahashi |
2 | satou |
2 | yamamoto |
下記のようなイメージでインデックス付けがされます。
複合インデックスの利用
インデックスを効かせるためには、設定時の順番を意識しなければなりません。下記のようにインデックス通りに指定した場合は効いていることが直感的にもわかると思います。
// groupとnameを指定
collection.find(
Filters.and(
Filters.eq("group", 1),
Filters.eq("name", "satou")));
ところが、"name"のみを指定した場合、
// nameを指定
collection.find(Filters.eq("name", "satou"));
途中のgroupが抜けており、Rootからたどれないためインデックスが効きません(※1)。
ソートにおいても同様に、B木の構造と走査方向を意識しましょう。
collection.find().sort(new Document("group", 1).append("name", 1));
であれば設定どおりのため、インデックスが効きますが、
collection.find().sort(new Document("group", 1).append("name", -1));
では、途中で逆走が入ってしまいインデックスが効きません。B木は基本的に1方向に走査する設計になっています。
なので、下記のように全部逆走するのであれば、インデックスが効くことになります。
collection.find().sort(new Document("group", -1).append("name", -1));
インデックス設計方針
ここまで上げたようにB木であることの特性を理解しつつ、下記の公式ドキュメントを参考にインデックス設計を考えるのが良いかと思います。
ESR(Equality, Sort, Range)ガイドライン
注釈
- ※1:ここまでシンプルな場合は、実際の動作としてはMongoDB側で上手いこと補ってインデックスが効くケースもあります。explainで動作を確認しましょう。