MongoDB単一フィールドインデックスと複合インデックス


MongoDBでよく見られるインデックスには、単一フィールドインデックスと複合インデックスがある.
単一フィールド索引
インデックスのないクエリー
>db.users.find({username:"user0115"}).explain(true)
//         ,     docsExamined 100W,         ,      executionTimeMillis 318ms
//db.users.find({username:"user123456"}).explain(true).executionStats.executionTimeMillis            

    "executionStats" : {
    .....
        "executionSuccess" : true,
        "executionTimeMillis" : 318,
        "nReturned" : 1,
        "totalDocsExamined" : 1000000,
        "totalKeysExamined" : 0
    .....
    }

インデックスの作成
今回はusernameにインデックスを新規作成し、1はインクリメンタル配列を示します.
>db.users.ensureIndex({"username":1})

インデックス解析
db.users.find({username:"user0115"}).explain(true)
//    ,   indexName          , executionTimeMillis 0ms,totalDocsExamined 1,     1   ,       
....
                "indexName" : "username_1",
                "indexVersion" : 1,
                "invalidates" : 0,
                "isEOF" : 1,
                "isMultiKey" : false,
                "isPartial" : false,
                "isSparse" : false,
                "isUnique" : false,
                "keyPattern" : {
                    "username" : 1
                }
......
        "executionSuccess" : true,
        "executionTimeMillis" : 0,
        "nReturned" : 1,
        "totalDocsExamined" : 1,
        "totalKeysExamined" : 1
.....

注意事項
新しいインデックスを作成すると、ドキュメントを更新(挿入、更新、削除)するたびにインデックスが更新されます.MongoDBは、各集合に最大64個のインデックスしかないことを制限する.通常、1つの特定の集合において、2つ以上のインデックスを持つべきではない.通常、インデックスは、一般的なクエリーのフィールドに作成するべきであり、一般的でないフィールドに対してインデックスを作成するべきではない.
複合インデックス
インデックスに対応する値は一定の順序で配列するため、インデックスを用いる文書の並べ替えが非常に速い.しかし、ソートを行う場合は、1つのインデックスしか使用できません.使用するインデックスを最初の位置に置く必要があります.以下の例では、集合中のデータ量が比較的大きいため、直接並べ替えは、MongoDBの1回の操作に対するメモリ制限32 Mを超える.従って、以下の操作で用いるusers集合データ量は10 Wである.
>db.users10W.find().sort({"age": 1 , "username" : 1}).limit(1000)

上記の例ではageをソートしてからusernameをソートする.usernameにインデックスを作成しましたが、このクエリはusernameインデックスには使用できません.explain情報のクエリー
        .....
        "memLimit" : 33554432,
        "memUsage" : 98341,
        .....
        "executionSuccess" : true,
        "executionTimeMillis" : 124,
        "nReturned" : 1000,
        "totalDocsExamined" : 100000,
        "totalKeysExamined" : 0
        .....

メモリが98 Kを使用していることを発見し、すべての10 Wのドキュメントをスキャンし、124 msを費やした.
複合インデックスの作成
このクエリが比較的一般的である場合、複合インデックス(compound index)と呼ばれる2つのフィールドにインデックスを一緒に作成することができる.このインデックスは、クエリに複数のソートがある場合や、クエリ条件に複数のキーがある場合に便利です.
>db.users10W.ensureIndex({"age":1,"username":1})
>db.users10W.getIndexes()
{
    "key" : {
        "_id" : NumberInt("1")
    },
    "name" : "_id_",
    "ns" : "test.users10W",
    "v" : NumberInt("1")
},

{
    "key" : {
        "username" : 1
    },
    "name" : "username_1",
    "ns" : "test.users10W",
    "v" : NumberInt("1")
},
{
    "key" : {
        "age" : 1,
        "username" : 1
    },
    "name" : "age_1_username_1",
    "ns" : "test.users10W",
    "v" : NumberInt("1")
}

コンポジットインデックス解析
3つ目は新しく追加した複合インデックスであることがわかる.上記のクエリとexplain情報を再度行う.1000個のドキュメントを返し、1000個のドキュメントをスキャンするだけで、1 msかかります.以前のインデックスが使用されていなかった場合、すべてのドキュメントをスキャンし、124 msかかりました.
        ...
        "executionSuccess" : true,
        "executionTimeMillis" : 1,
        "nReturned" : 1000,
        "totalDocsExamined" : 1000,
        "totalKeysExamined" : 1000
        .....
                    "indexName" : "age_1_username_1",
                    "indexVersion" : 1,
                    "isMultiKey" : false,
                    "isPartial" : false,
                    "isSparse" : false,
                    "isUnique" : false,
                    "keyPattern" : {
                        "age" : 1,
                        "username" : 1
                    },
        ....

結論
単純なインデックスでも複合インデックスでも.正しく使用する場合、クエリーの速度が大幅に速くなります.
ステートメント
コレクションサイズ
インデックスの状況
時間がかかる
スキャンドキュメント数
db.users.find({username:”user0115”})
1M
なし
318ms
1M
db.users.find({username:”user0115”})
1M
db.users.ensureIndex({“username”:1})
0ms
1
db.users10W.find().sort({“age”: 1 , “username” : 1}).limit(1000)
0.1M
なし
124ms
0.1M
db.users10W.find().sort({“age”: 1 , “username” : 1}).limit(1000)
0.1M
db.users10W.ensureIndex({“age”:1,”username”:1})
1ms
1000
要点:索引の問合せ:
db.users10W.getIndexes()
インデックスの作成:
単純インデックス:db.users.ensureIndex(「username」:1})複合インデックス:db.users10W.ensureIndex({“age”: 1,”username”: 1})
索引の削除
db.users10W.dropIndex(“username_1”)