MongoDBのインデックス

47372 ワード

一.索引詳細
インデックスとは何か、インデックスは本のディレクトリのようなもので、ある章を探したいときは、本のディレクトリを通じてすぐに見つけることができるので、インデックスを適切に追加することで、クエリーのデータの速度を高めることができます.
仕事を準備して、MongoDBに20000本の記録を挿入して、記録がなくてすべてnumberとnameがあります
> for(var i = 0 ; i<200000 ;i++){
... db.books.insert({number:i,name:"book"+i})
... }
WriteResult({ "nInserted" : 1 })
> db.books.find({},{_id:0})
{ "number" : 0, "name" : "book0" }
{ "number" : 1, "name" : "book1" }
{ "number" : 2, "name" : "book2" }
{ "number" : 3, "name" : "book3" }
{ "number" : 4, "name" : "book4" }
{ "number" : 5, "name" : "book5" }
{ "number" : 6, "name" : "book6" }
{ "number" : 7, "name" : "book7" }
……
>

1.インデックスの追加とインデックスの追加を行わないクエリの効率性の比較
例:クエリnumber 65535のname
インデックスを使用しない場合、クエリー時間はmillisをご覧ください
> db.books.find({number:65535},{_id:0,name:1}).explain()
{
        "cursor" : "BasicCursor",
        "isMultiKey" : false,
        "n" : 1,
        "nscannedObjects" : 200000,
        "nscanned" : 200000,
        "nscannedObjectsAllPlans" : 200000,
        "nscannedAllPlans" : 200000,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 1562,
        "nChunkSkips" : 0,
        "millis" : 172,
        "server" : "G08FNSTD131598:27017",
        "filterSet" : false
}
>

インデックスを使用する場合は、単純なインデックスを作成しnumberでインデックスを作成します.
 db.books.ensureIndex({number:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.books.find({number:65535},{_id:0,name:1}).explain()
{
        "cursor" : "BtreeCursor number_1",
        "isMultiKey" : false,
        "n" : 1,
        "nscannedObjects" : 1,
        "nscanned" : 1,
        "nscannedObjectsAllPlans" : 1,
        "nscannedAllPlans" : 1,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
"indexBounds" : {
                "number" : [
                        [
                                65535,
                                65535
                        ]
                ]
        },
        "server" : "G08FNSTD131598:27017",
        "filterSet" : false
}
>

上から分かるように、クエリの時間にインデックスが付いている場合は明らかに短縮されます.
 
2.挿入したデータの時間的比較
作成したbooksドキュメントを削除する準備
時間の記録とデータの挿入を完了する関数を定義します.
> var time = function(){
... var start = new Date();
... for(var i = 0;i < 200000 ; i++){
... db.books.insert({number:i,name:"book"+i});
... }
... var end = new Date();
... return end - start;
... }

インデックスを追加しない場合:
> var x = time();
> x
63057

索引の作成
> db.books.ensureIndex({number:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}

インデックスが存在する場合のデータ挿入にかかる時間
> var x = time();
> x
67223

インデックスが存在しない場合、挿入されたデータの時間が短いことがわかります
以上:ドキュメントを頻繁に挿入する必要がある場合、あいにくインデックスを作成すると、挿入効率が低下します.
 
3.インデックスを作成する上で注意すべき点
インデックスを作成するとき注意1は正の順序でインデックスを作成します-1は逆の順序でインデックスを作成します
インデックスの作成は、クエリーのパフォーマンスを向上させる同僚によって挿入のパフォーマンスに影響します.
頻繁にクエリが挿入されないドキュメントについては、インデックスを使用することが考えられます.
インデックスに一致するインデックスの優先順位に注意
すべてのキーにインデックスを作成すると、必ずしもパフォーマンスが向上するわけではありません.インデックスは万能ではありません.
ソート作業を行う際には、大きなデータ量であればインデックスを加えてソートのパフォーマンスを向上させることも考えられます.
 
4.インデックスの作成の詳細
①インデックスを作成するときにensureIndex()という方法を使ってインデックスを作成します.名前はキーの名前にnumber_1またはnumber_-1は正の索引、-1は逆の索引
②1や-1は覚えにくいと思う場合は、カスタム名を使ってインデックスを作成することもできます
> db.books.ensureIndex({name:1},{name:"bookNameIndex"})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "ok" : 1
}

③1つのドキュメントに複数のインデックスが作成されていますが、1つのインデックスを強制的に使用したいのですが、どうすればいいですか
たとえば、上記のドキュメントでnumberに逆シーケンスインデックスを作成し、nameに正シーケンスインデックスを作成しました.今、検索するときにnameでインデックスを作成したい場合は、次のように書きます.
> db.books.find({name:"book2016"},{_id:0}).hint({name:1})
{ "number" : 2016, "name" : "book2016" }
{ "number" : 2016, "name" : "book2016" }
>

作成されていないインデックスを使用すると、bad hintのエラーが返されます.
④使用するインデックスとクエリーデータのステータス情報を表示し、explain()メソッドを使用する
> db.books.find({name:"book2016"},{_id:0}).hint({name:1}).explain()
{
        "cursor" : "BtreeCursor bookNameIndex",
        "isMultiKey" : false,
        "n" : 2,
        "nscannedObjects" : 2,
        "nscanned" : 2,
        "nscannedObjectsAllPlans" : 2,
        "nscannedAllPlans" : 2,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "indexBounds" : {
                "name" : [
                        [
                                "book2016",
                                "book2016"
                        ]
                ]
        },
        "server" : "G08FNSTD131598:27017",
        "filterSet" : false
}

私たちのインデックスの名前はbookNameIndexで、millisは0で、nscannedはいくつかのドキュメントを調べました.
⑤リレーショナル・データベースで食べてみると制約があり、よく使われるのが一意性で、MongoDBでも一意を指定できます
ユニークなインデックスの作成:db.books.ensureIndex({name:-1},{unique:true})
インデックスとインデックスなしでまったく同じデータのセットを挿入しましたが、一意のインデックスを作成するとエラーが発生します.
> db.books.ensureIndex({name:1},{unique:true})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "ok" : 0,
        "errmsg" : "E11000 duplicate key error index: mongoDBTest.books.$name_1
 dup key: { : \"book0\" }",
        "code" : 11000
}

この場合dropDups:true属性で重複するデータを削除できます
> db.books.ensureIndex({name:1},{unique:true,dropDups:true})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
>

重複を削除し、同じ名前のデータを追加すると、次のような状況になります.
> db.books.insert({number:1,name:"book1"})
WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 11000,
                "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicat
e key error index: mongoDBTest.books.$name_1  dup key: { : \"book1\" }"
        }
})
>

⑥索引の削除
削除するインデックスの指定
db.runCommand({dropIndexes : ”books” , index:”name_-1”})
すべてのインデックスを削除
db.runCommand({dropIndexes : ”books” , index:”*”})
注:インデックスの作成時に同期されるので、非同期のインデックスの作成を指定するには、バックグラウンドで作成するように指定します.
db.books.ensureIndex({name:-1},{background:true})
 
二.スペースインデックス
2 Dインデックスは、例えば、1つの領域に座標系を確立すると、多くの場所が1つの座標と見なすことができ、2 dインデックスは、ある範囲の場所を迅速に検索するのに役立ちます.
例:MongoDBで多くの座標点を持つドキュメントを作成します.
> db.map.find({},{_id:0})
{ "gis" : { "x" : 185, "y" : 150 } }
{ "gis" : { "x" : 70, "y" : 180 } }
{ "gis" : { "x" : 75, "y" : 180 } }
{ "gis" : { "x" : 185, "y" : 185 } }
{ "gis" : { "x" : 65, "y" : 185 } }
{ "gis" : { "x" : 50, "y" : 50 } }
{ "gis" : { "x" : 50, "y" : 100 } }
{ "gis" : { "x" : 60, "y" : 55 } }
{ "gis" : { "x" : 65, "y" : 80 } }
{ "gis" : { "x" : 55, "y" : 80 } }
{ "gis" : { "x" : 0, "y" : 0 } }
{ "gis" : { "x" : 0, "y" : 200 } }
{ "gis" : { "x" : 200, "y" : 0 } }
{ "gis" : { "x" : 200, "y" : 200 } }
>

1.2 Dインデックスを追加
db.map.ensureIndex({"gis":"2d"},{min:-1,max:201})
デフォルトでは、[-18080]間の2 Dインデックスが作成されます.
例:
①クエリポイント(70180)最近の3点
> db.map.find({"gis":{$near:[70,180]}},{gis:1,_id:0}).limit(3)
{ "gis" : { "x" : 70, "y" : 180 } }
{ "gis" : { "x" : 75, "y" : 180 } }
{ "gis" : { "x" : 65, "y" : 185 } }

②ポイント(50,50)とポイント(190190,190)を対角線とする正方形のすべてのポイントを問い合わせる
> db.map.find({gis:{$within:{$box:[[50,50],[190,190]]}}},{_id:0,gis:1})
{ "gis" : { "x" : 185, "y" : 150 } }
{ "gis" : { "x" : 75, "y" : 180 } }
{ "gis" : { "x" : 70, "y" : 180 } }
{ "gis" : { "x" : 65, "y" : 185 } }
{ "gis" : { "x" : 50, "y" : 100 } }
{ "gis" : { "x" : 65, "y" : 80 } }
{ "gis" : { "x" : 55, "y" : 80 } }
{ "gis" : { "x" : 60, "y" : 55 } }
{ "gis" : { "x" : 50, "y" : 50 } }
{ "gis" : { "x" : 185, "y" : 185 } }
>

③円心を(56,80)半径50とする規則の円心面積の点を検索する
> db.map.find({gis:{$within:{$center:[[56,80],50]}}},{_id:0,gis:1})
{ "gis" : { "x" : 55, "y" : 80 } }
{ "gis" : { "x" : 50, "y" : 100 } }
{ "gis" : { "x" : 50, "y" : 50 } }
{ "gis" : { "x" : 60, "y" : 55 } }
{ "gis" : { "x" : 65, "y" : 80 } }