概要
MongoDBのインデックスにはIndex Intersection
やCovered Index
なんてのもあるので調べてみました。
環境
- Ubuntu 14.04
- MongoDB 2.6.8
Index Intersectionとは
1つのクエリーで2つのインデックスを使ってくれる機能で、より効率的にクエリーを処理できる
というもの。
簡単に言うと複合インデックスが必要なクエリをMongoDB側でうまくインデックスを組み合わあわせてよろしくやってくれる機能といった感じでしょうか。
基本的な使い方
db.collection.find({a: xxx, b: yyy})
といったクエリを投げるとき、最適なインデックスは
ensureIndex({a: 1, b: 1})
ですが、Index Intersectionがあると
ensureIndex({a: 1}) ensureIndex({b: 1})
という2つのインデックスをつけていればMongoDB側でうまく組み合わせてくれるという機能です。
じゃあ複合インデックスは要らない?
そんなことはないです。以下に複合インデックスとIndex Intersectionの比較を記します。
複合インデックス | Index Intersection |
---|---|
速い。インデックスをフルに活用。 ちゃんとつければ外部ソートも起きにくい。 |
柔軟性。クエリ専用のインデックスを つけていなくても効果を発揮 |
なので用途に応じて使い分けるといいです。
参照系のコレクションなら複合インデックスの方が向いてるでしょうし、更新系のコレクションならIndex Intersectionの方が負荷が低いと思います。
ソートの場合、完全別のインデックスは外部ソートになる
ensureIndex({a: 1}) ensureIndex({b: 1})
とした時に
find({a: xxx}).sort({b: 1})
としても外部ソートであまり効果はありません。
ensureIndex({a: 1}) ensureIndex({b: 1, c: 1})
のときに
find({a: xxx, b: yyy}).sort({c: 1})
のようにまたがる場合はだったら有効です。
prefixesは有効
ensureIndex({a: 1}) ensureIndex({b: 1, c: 1})
のときは
find({a: xxx, b: yyy})
でも
find({a: xxx, b: yyy, c: zzz})
でも有効です。
その他注意
以下のケースではIndex Intersectionは使えません。
- rangeクエリを含む
Covered Queryとは
インデックスにデータを保持させることで、実データを取得せずインデックスだけですぐに結果を返す仕組みです。
基本的な使い方
以下の様なドキュメントを持つコレクションtests
があるとします。
{ _id: ObjectId(), a: 10, b: "hogehoge", c: "fugafuga", d: 100, }
このドキュメントでほしい情報はa
、b
だけといったときに、Covered Queryが活躍します。
インデックスを以下のようにつけ、
> db.tests.ensureIndex({a: 1, b: 1})
クエリを以下のようにすれば、実データにアクセスしないためメモリ上で処理してくれます。
> db.tests.find({a: xxx}, {a: 1, b: 1, _id: 0})
注意なのは_id: 0
の部分です。_id
は基本的に勝手についてくるので明示的に消す必要があります。
なぜなら_id
は複合インデックスに入っていないので、非表示にしないと実データにアクセスしてしまうからです。
その他注意
以下のケースではCovered Queryは使えません。
- インデックスをつけたフィールドがarray
- インデックスをつけたフィールドがサブドキュメント(ネストしたやつ)
- シャードで分散構成になっている場合