分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
MongoDB支持复合索引,即将多个键组合到一起创建索引。该方式称为复合索引,或者也叫组合索引,该方式能够满足多键值匹配查询使用索引的情形。其次复合索引在使用的时候,也可以通过前缀法来使用索引。MongoDB中的复合索引与关系型数据库基本上一致。在关系型数据库中复合索引使用的一些原则同样适用于MongoDB。本文主要描述MongoDB复合索引。
一、复合索引相关概述
1、复合索引创建语法 db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } ) 同创建单键(列)索引一样,索引创建时需要指定每一个键索引的顺序 多个键直接用逗号分隔 索引创建语法可以参考:http://blog.csdn.net/leshami/article/details/535419782、复合索引的一些特性 复合索引可以支持要求匹配多个键的查询 复合索引每一个键的顺序非常重要,这将决定该索引在查询过程中能否被使用到 复合索引支持前导(缀)列索引查询 不能够创建基于哈希索引类型的复合索引 任意复合索引字段不能超过31个
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
二、复合索引示意图
如下图所示,在集合的userid以及score列上创建一个复合索引,其中userid为升序,score为降序
三、复合索引示例
1、演示环境
> db.version()3.2.10> db.example.find({},{"_id":0}){ "id" : 1, "ename" : "leshami", "blog" : "http://blog.csdn.net/leshami", "name" : "leshami" }演示集合数据,可以参考:http://blog.csdn.net/leshami/article/details/52672310//查看任意的一个文档> db.persons.find().limit(1).pretty(){ "_id" : ObjectId("5812cbaaa129eed14b46458d"), "name" : "robinson.cheng", "age" : 25, "email" : "robinson.cheng@qq.com", "score" : { "c" : 89, "m" : 96, "e" : 87 }, "country" : "USA", "books" : [ "JS", "C++", "EXTJS", "MONGODB" ]}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
2、创建复合索引
//如下示例,我们在集合persons上的name及age键上创建复合索引,且2个都为升序> db.persons.createIndex({name:1,age:1}){ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1}//在上面的示例中索引首先会按照name的值升序进行排列//其次是age键,在name之后也按照升序排列//下面过滤条件仅使用一个name键来查看执行计划> db.persons.find({name:"robinson.cheng"}).explain(){ ...... "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", //使用索引扫描 "keyPattern" : { "name" : 1, "age" : 1 }, "indexName" : "name_1_age_1", ...... "direction" : "forward", "indexBounds" : { "name" : [ "[\"robinson.cheng\", \"robinson.cheng\"]" ], "age" : [ "[MinKey, MaxKey]" ......... "ok" : 1}//下面过滤条件仅使用name及age键来查看执行计划> db.persons.find({name:"robinson.cheng",age:25}).explain(){ ......... "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", //使用索引扫描 "keyPattern" : { "name" : 1, "age" : 1 }, "indexName" : "name_1_age_1", ......... "direction" : "forward", "indexBounds" : { "name" : [ "[\"robinson.cheng\", \"robinson.cheng\"]" ], "age" : [ "[25.0, 25.0]" ........... "ok" : 1}//下面过滤条件仅使用name及age键来查看执行计划,但是将age键放在name键之前> db.persons.find({age:25,name:"robinson.cheng"}).explain(){ "queryPlanner" : { ..... "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", //使用索引扫描 "keyPattern" : { "name" : 1, "age" : 1 }, "indexName" : "name_1_age_1", ........... "direction" : "forward", "indexBounds" : { "name" : [ "[\"robinson.cheng\", \"robinson.cheng\"]" ], "age" : [ "[25.0, 25.0]" ........ "ok" : 1}//下面单独基于age键作为过滤条件进行查询> db.persons.find({age:25}).explain(){ ................ "winningPlan" : { "stage" : "COLLSCAN", //此处为使用集合扫描方式 "filter" : { "age" : { "$eq" : 25 } }, "direction" : "forward" }, "rejectedPlans" : [ ] .............. "ok" : 1}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
3、复合索引与排序
复合索引创建时按升序或降序来指定其排列方式。对于单键索引,其顺序并不是特别重要,因为MongoDB可以在任一方向遍历索引对于复合索引,按何种方式排序能够决定该索引在查询中能否被使用到。//以下内容基于前面在{name:1,age:1}键上创建的索引来考察这个复合索引在排序时被使用到的场景//基于{name:1,age:1}的排序> db.persons.find().sort({name:1,age:1}).explain(){ "queryPlanner" : { .... "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", //索引扫描 "keyPattern" : { "name" : 1, "age" : 1 }, "indexName" : "name_1_age_1", .......... "direction" : "forward", "indexBounds" : { "name" : [ "[MinKey, MaxKey]" ], "age" : [ "[MinKey, MaxKey]" .... "ok" : 1}//基于{name:1,age:-1}的排序> db.persons.find().sort({name:1,age:-1}).explain(){ "queryPlanner" : { .... "winningPlan" : { "stage" : "SORT", "sortPattern" : { "name" : 1, "age" : -1 }, "inputStage" : { "stage" : "SORT_KEY_GENERATOR", "inputStage" : { "stage" : "COLLSCAN", //集合扫描 "filter" : { "$and" : [ ] }, "direction" : "forward" ......... "ok" : 1}//基于{name:-1,age:1}的排序> db.persons.find().sort({name:-1,age:1}).explain(){ "queryPlanner" : { ......... "winningPlan" : { "stage" : "SORT", "sortPattern" : { "name" : -1, "age" : 1 }, "inputStage" : { "stage" : "SORT_KEY_GENERATOR", "inputStage" : { "stage" : "COLLSCAN", //集合扫描 "filter" : { "$and" : [ ] }, "direction" : "forward" ......... "ok" : 1}//基于{age:1,name:1}的排序> db.persons.find().sort({age:1,name:1}).explain(){ .... "inputStage" : { "stage" : "SORT_KEY_GENERATOR", "inputStage" : { "stage" : "COLLSCAN", //集合扫描 "filter" : { "$and" : [ ] }, "direction" : "forward" .......... "ok" : 1}//基于{age:-1,name:1}的排序> db.persons.find().sort({age:-1,name:1}).explain(){ .......... "inputStage" : { "stage" : "SORT_KEY_GENERATOR", "inputStage" : { "stage" : "COLLSCAN", //集合扫描 "filter" : { "$and" : [ ] }, "direction" : "forward" .......... "ok" : 1}//基于{name:-1,age:-1}的排序> db.persons.find().sort({name:-1,age:-1}).explain(){ ......... "inputStage" : { "stage" : "IXSCAN", //索引扫描 "keyPattern" : { "name" : 1, "age" : 1 }, "indexName" : "name_1_age_1", ............ "direction" : "backward", //注意,这里的方向为向后扫描 "indexBounds" : { "name" : [ "[MaxKey, MinKey]" ], "age" : [ "[MaxKey, MinKey]" ...... "ok" : 1}通过上面的不同场景,得出如下:排序使用到索引的情形 db.persons.find().sort({name:1,age:1}) db.persons.find().sort({name:-1,age:-1})排序未使用到索引的情形 db.persons.find().sort({name:1,age:-1}) db.persons.find().sort({name:-1,age:1}) db.persons.find().sort({age:1,name:1}) db.persons.find().sort({age:-1,name:1})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
4、复合索引与索引前缀
索引前缀指的是复合索引的子集 假如存在如下索引 { "item": 1, "location": 1, "stock": 1 } 那存在下列索引前缀 { item: 1 } { item: 1, location: 1 } 在MongoDB中,下列查询过滤条件情形中,索引将会被使用到 item字段 item字段 + location字段 item字段 + location字段 + stock字段 item字段 + location字段(尽管索引被使用,但不高效) 以下过滤条件查询情形,索引将不会被使用到 location字段 stock字段 location + stock字段
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
5、小结
a、复合索引是基于多个键(列)上创建的索引
b、复合索引在创建的时候可以为其每个键(列)来指定排序方法
c、索引键列的排序方法影响查询在排序时候的操作,方向一致或相反的才能被匹配
d、复合索引与前缀索引通常在匹配的情形下才能被使用