ボクココ

個人開発に関するテックブログ

MongoDB の Index 入門

最近はひたすらMongoDB について学習中。 日本語の書籍が全くないので、英語で。ちょいと時間がかかるが英語と一緒に勉強できるからいい感じだ。

さて、MongoDBの CRUD 系は割とどこの本でも同じようなことを書いてあるが、今回読んでる本はindex についてわかりやすかったのでブログにまとめておくとしよう。

index は where と sort で効果を発揮する

まぁ当たり前っちゃ当たり前。本に付箋を貼るのも where で検索しやすいようにするためだからね。 でも index 付与の時は、複数の find条件や sort があったりしたときに、どうindexをつかえるのかが大事になる。 まず一番シンプルなのは、

db.test.find({"name": "hoge"})

ってパターン。これは純粋に

db.test.ensureIndex({"name": 1})

でおk。ハイ次。

db.test.find({"name": "hoge"}).sort({"age": 1})

このとき覚えておく必要があるのが、indexは昇順にソートされる順番だと考えておくこと。つまり、

db.test.ensureIndex({"age": 1, "name" : 1})

とするとよい。順番が逆だと、 まずnameの順番でソートされた結果を取ってきてしまうので、メモリ内でさらにageでソートする必要がでてきてしまうからだ。

二つ以上の sort 条件がある場合は昇順か降順かにも気を使う必要がある。 これもソート条件によってindexを付与する順番が変わる。

もし名前を昇順でソートして、かぶってたらageの降順とした場合は

db.test.ensureIndex({"name": 1, "age" : -1})

となる。これは複数のソート条件があった場合のみなので、単純に1つのソートだけでfind条件を特に気にしないなら `{“age”: -1}, {“age”:1}“のどちらかを貼ればよい。

また、indexの付与の順番によって以下の決まりがある。これも”indexは昇順にソートされる順番”ということを念頭に置いておけば理解できる。

例えば {“a”:1, “b”:1, “c”:1, “d”:1} ってindexがあったときに、それは {“a”:1} や {“a”:1, “b”:1} というindexも適用されていることになる。でも {“b”:1, } や {“a”:1, “c”:1} といったindexは適用されない。そのような場合は別途indexを作る必要がある。

ソートがある場合はfindでとってきたあとにちゃんと既にソートされた状態であることが 大事だ。それを認識すれば効果的にindexが付与できるようになる。

こういったindexの調査は find({….}).explain() でみることができる。indexは貼り直せたりするので、はじめのうちは消したり追加したりして試行錯誤するのがいいと思う。

カーディナリティ

indexを where で指定するときに大事なのがこれ。 カーディナリティが高いとは、ユニーク性が高いカラムであること示す。メアドとかユーザ名とか重複しないように設計されているのはカーディナリティが高い。これらをまず優先的にindexを貼っておくことで、たくさん絞ってからソートしたり他のwhereを適用するので、とても効率がよくなる。 where で複数指定する時はこのことを考慮に入れる必要がある。

indexが使えないクエリ

せっかくindexを作ったのに、クエリがよろしくないとちゃんとデータを高速で取ってくることができない。たとえば $where. 割と柔軟に条件を指定できる便利なものだが、これはindexが効かない。また、 $ne や $nin などの否定系。これらもできる限り使用を避けないと効率の悪いクエリができていってしまう。どうしても使わないと行けない場合は、他の効いているindexで絞ってからそれらを使うようにするといいそうだ。

MongoDBは1つのクエリに対して1つのindexしか適用できない。 $or を使った場合、これはそれぞれの条件で検索をかけて、最後にマージすることで答えを出す。これらは効率的であるとは言えないので、できる限り"$in" で対応できるようにしよう。

まだindexについての話 (ArrayやEmbed Documentのindex) が続いているので、続編あるかも。 英語でなんとなく理解した程度なので、指摘等あれば歓迎します。