インデックス

based on v49

インデックスはクエリーのパフォーマンスを(とても)向上させます。有効なインデックスを定義するためには、アプリケーションが必要とするクエリについてよく知ることが大切です。それさえできていれば、MongoDBでインデックスを作成するのは簡単です。

MongoDBのインデックスは、MySQLのようなRDBMSのインデックスと概念的に似ています。MySQLでインデックスを付けたいような場所に、MongoDBでもインデックスを付けることになるでしょう。

基本

インデックスは、コレクションの中のドキュメントの特定のフィールドの値について集めたデータ構造です。このデータ構造はMongoのクエリオプティマイザによって、コレクション内のドキュメントを、素早く検索したりソートするために使われます。正式な言い方で言うと、インデックスは"B-Tree"で実装されています。

シェル 上で、 ensureIndex() を1つ以上のキーを指定し呼ぶことでインデックスを作ることができます。 チュートリアル で作成した 例で作成した データベースを使い、 下記のように'j'フィールドにインデックスを作成してみます。

db.things.ensureIndex({j:1});

ensureIndex() ファンクションはインデックスが存在したいない場合に限りインデックスを作成します。

一度コレクションにキーにインデックスが作成されたら、キーにマッチするクエリでのランダムアクセスが速くなります。インデックスなしでは、MongoDBは、各クエリーで、すべてのドキュメントを指定されたキーで検索する必要があります。

db.things.find({j : 2}); // インデックス使用、速い
db.things.find({x : 3}); // 'x'はインデックスではないのですべてチェックする必要がある、遅い
デフォルトのインデックス

_id には常にインデックスが生成されます。このインデックスは特別で削除することはできません。 _id に対するインデックスは、ユニーク制約をそのキーに設定します。

埋め込みキー (embedded keys)

MongoDBでは、埋め込みのドキュメント内のキーにもインデックスを作成できます。たとえば、

db.things.ensureIndex({"address.city": 1})
キーとしてのドキュメント

インデックスは、ドキュメントを含むどんなタイプのフィールドにも設定できます。

db.factories.insert( { name: "xyz", metro: { city: "New York", state: "NY" } } );
db.factories.ensureIndex( { metro : 1 } );
// このクエリで、このインデックスを使います。
db.factories.find( { metro: { city: "New York", state: "NY" } } );

これをする代わりに、ドキュメントの複数のキー対して複合インデックスを作成するという方法もあります。

db.factories.ensureIndex( { "metro.city" : 1, "metro.state" : 1 } );
// 次のクエリで、このインデックスを使います。
db.factories.find( { "metro.city" : "New York", "metro.state" : "NY" } );
db.factories.find( { "metro.city" : "New York" } );
db.factories.find().sort( { "metro.city" : 1, "metro.state" : 1 } );
db.factories.find().sort( { "metro.city" : 1 } )

この二つの方法には、メリットとデメリットがそれぞれあります。キーとして(サブ)ドキュメント自体を使う場合、比較順序が、予め定義されたものなり、 [BSON] での昇順になります。複合インデックスでは、昇順、降順を混ぜることができます。また、クエリオプティマイザでは、インデックスの最初のキーのインデックスだけを使うこともできます。

配列

インデックスで指定したフィールドに配列が保存された場合、MongoDBは配列のそれぞれの要素に対してインデックスを作成します。詳しくは Multikeys を参照してください。

複合キーインデックス

シングルキー インデックスに加え、MongoDBは複数のキーに対する"複合"インデックスをサポートしてます。基本的なインデックスと同じように、 シェル 内で ensureIndex() を使いインデックスを作成しますが、1つのキーを指定する変わりに、複数のキーを指定します。

db.things.ensureIndex({j:1, name:-1});

インデックスを作成するとき、キーの指定と一緒についている数字は、インデックスのソート順です。1 (昇順) または -1 (降順) になります。 ソート順はシングルキーインデックスやランダムアクセスでは関係ありませんが、複合キーでのソートや範囲を指定したクエリーでは重要です。

複数のフィールドにインデックスがある場合、フィールドの最初の方から部分的にクエリに使うことができます。たとえば、

a,b,c

にインデックスがある場合、

a
a,b
a,b,c

をクエリで使うことができます。

ユニークインデックス

MongoDBはユニークインデックスをサポートしています。これは、インデックスに対し、同じキーが存在するドキュメントがないことを保証するものです。 firstnamelastname の両方のフィールドで同じ値を持つ2つドキュメントが存在しないことを保証するためにインデックスを作るためには、

db.things.ensureIndex({firstname: 1, lastname: 1}, {unique: true});
存在しなキー

ユニークインデックスを持つコレクションがセーブされたとき、値が存在しないキーはnull値として保存されます。したがって、複数の存在しないキーを持ったドキュメントを持つことができないことになります。

 db.things.ensureIndex({firstname: 1}, {unique: true});
db.things.save({lastname: "Smith"});

//firstnameがユニークインデックスなので次の操作は失敗します。
db.things.save({lastname: "Jones"});
重複した値

重複する値があるキーにはユニークインデックスを作成することはできません。どうしてもユニークインデックスを作成したい場合には、 dropDups オプションを指定すると、最初のドキュメントだけを残し、重複するすべてのドキュメントを削除します。

db.things.ensureIndex({firstname : 1}, {unique : true, dropDups : true})

インデックスの削除

指定したコレクションのすべてのインデックスを削除するには、

db.collection.dropIndexes();

一つのインデックスを削除するには、

db.collection.dropIndex({x: 1, y: -1})

ヘルパーなしでコマンドとして直接実行します

// 注意: MongoDB v1.3.2 より前では、"dropindexes"ではなく"deleteIndexes"でした。
// キーパターン {y:1} のインデックスをコレクションfooから削除
db.runCommand({dropIndexes:'foo', index : {y:1}})
// すべてのインデックスを削除
db.runCommand({dropIndexes:'foo', index : '*'})

インデックスの再作成

reIndex コマンドでコレクションのすべてのインデックスを再生成できます。

 db.myCollection.reIndex()
// 下記も同じことです
db.runCommand( { reIndex : 'myCollection' } )

通常、これをする必要はありません。コレクションのサイズが大きく変わったり、インデックスが使っているディスク容量が不自然に大きい場合に使うことがあります。

repair database はすべてのインデックスを再生成します。

インデックスに関するその他のこと

  • MongoDBindex (一般的に文字列の評価) はケースセンシティブです。
  • オブジェクトを アップデート するときに、オブジェクトが元々割り当てられていたサイズに収まる場合には、キーの値が変更された場合のみインデックスは更新されます。これはパフォーマンスを向上させます。注意: オブジェクトサイズが大きくなり移動が行われると、オブジェクトのすべてのインデックスが更新されます。これは遅いです。
  • インデックス情報はシステム上のインデックスコレクションに保存されます。db.system.indexes.find() でサンプルデータを見ることができます。
インデックスの性能

インデックスは、キーを使い、範囲での検索を含めデータの取得をとても速くします。ドキュメントを素早く検索できるので、アップデートも速くなります。

しかし、インデックスは追加と削除に関してはいくらかのオーバーヘッドがあることを覚えておいてください。これは、コレクションへのデータの書き込みに加えて、キーはB-Tree インデックスにも加える必要があるからです。したがって、インデックスは書き込みより読み込みが多いコレクションではベストです。書き込みが多いコレクションに対し、インデックスは場合によっては逆効果です。しかし、ほとんどのコレクションは読み込みが多いものなので、インデックスは多くの場合で有効です。

sort() をインデックスなしで使う

結果のデータが少ない場合(4MB以下)、インデックスなしでも並び替えに sort() を使うことができます。この場合、 limit()sort() を一緒に使うのがベストです。

Geospatial

  • See [Geospatial Indexing] page.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

IF YOU HAVE A QUESTION, POST IT TO THE USER GROUP.

These pages are fine for comments, but for questions, your best bet will always be the MongoDB User Group.

blog comments powered by Disqus