MongoDB索引介绍

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 一、Single Field Indexes示例文档:{ "_id": ObjectId("570c04a4ad233577f97dc459"), "score": 1034, "location": { state: "NY", city: "New York" } }1、语法:db.

一、Single Field Indexes

示例文档:

{
"_id": ObjectId("570c04a4ad233577f97dc459"),
"score": 1034,
"location": { state: "NY", city: "New York" }
}

1、语法:

db.records.createIndex( { score: 1 } )

2、在嵌套字段上创建索引

db.records.createIndex( { "location.state": 1 } )

查询语法:

db.records.find( { "location.state": "CA" } )
db.records.find( { "location.city": "Albany", "location.state": "NY" } )

3、在嵌入式文档上创建索引

db.records.createIndex( { location: 1 } )

查询语法:

db.records.find( { location: { city: "New York", state: "NY" } } )

4、需要注意的点

对于以上location嵌套字段的查询,顺序与创建索引顺序不一致可以使用索引,但是查询结果记录为0,因为查询顺序不同。

示例:

> db.records.find()
{ "_id" : ObjectId("570c04a4ad233577f97dc459"), "score" : 1034, "location" : { "state" : "NY", "city" : "New York" } }
>
> db.records.find( { location: { city: "New York", state: "NY" } } )      //顺序相反,可以使用索引,但是返回0记录
>
> db.records.find( { location: { state: "NY",city: "New York" } } )      //顺序正确,返回1记录
{ "_id" : ObjectId("570c04a4ad233577f97dc459"), "score" : 1034, "location" : { "state" : "NY", "city" : "New York" } }

二、Compound Indexes

示例文档:

{
"item": "Banana",
"category": ["food", "produce", "grocery"],
"location": "4th Street Store",
"stock": 4,
"type": "cases"
}

1、语法

db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )

2、复合索引中包含的一些隐式索引

若我们集合中存在一个复合索引{a:1,b:1,c:1},在该索引下,相当于同时创建了如下一些索引:

{a:1,b:1,c:1}
<=> {a:1}
<=> {a:1,b:1}
<=> {a:1,b:1,c:1}

3、利用索引进行排序

示例:db.data.createIndex( { a:1, b: 1, c: 1, d: 1 } )

查询语句 使用索引
db.data.find().sort( { a: 1 } ) { a: 1 }
db.data.find().sort( { a: -1 } ) { a: 1 }
db.data.find().sort( { a: 1, b: 1 } ) { a: 1, b: 1 }
db.data.find().sort( { a: -1, b: -1 } ) { a: 1, b: 1 }
db.data.find().sort( { a: 1, b: 1, c: 1 } ) { a: 1, b: 1, c: 1 }
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } ) { a: 1, b: 1 }
db.data.find( { a: 5 } ).sort( { b: 1, c: 1 } ) { a: 1 , b: 1, c: 1 }
db.data.find( { b: 3, a: 4 } ).sort( { c: 1 } ) { a: 1, b: 1, c: 1 }
db.data.find( { a: 5, b: { $lt: 3} } ).sort( { b: 1 } ) { a: 1, b: 1 }

三、Multikey indexes

1、多键索引的创建

在数组上创建索引时,MongoDB会自动为该集合创建多键索引。

2、多键索引的唯一性

由于multikey indexes会对数组中每个值做索引,所以如果该字段设置为唯一多键索引,那需要保证该集合中index数组不能重复

1)示例集合

{ "_id" : 6, "type" : "food", "item" : "bbb", "ratings" : [ 5, 9 ] }
db.cc.createIndex({ratings:1},{unique:true})

2)唯一性验证

> db.cc.insert({"_id" : 5, "type" : "food", "item" : "aaa", "ratings" : [ 1,2 ]})    //[1,2]与[5,9]不冲突
WriteResult({ "nInserted" : 1 })
>
> db.cc.insert({"type" : "food", "item" : "aaa", "ratings" : [ 7,3 ]})        //[ 7,3 ]与[1,2,5,9]不冲突
WriteResult({ "nInserted" : 1 })
>
> db.cc.insert({"type" : "food", "item" : "aaa", "ratings" : [ 7,4 ]})        //7与[1,2,3,5,7,9]冲突
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "E11000 duplicate key error collection: test.cc index: ratings_1 dup key: { : 7.0 }"
    }
})
> db.cc.insert({"type" : "food", "item" : "aaa", "ratings" : [ 6,9 ]})      //9与[1,2,3,5,7,9]冲突
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "E11000 duplicate key error collection: test.cc index: ratings_1 dup key: { : 9.0 }"
    }
})
>
> db.cc.find()
{ "_id" : 6, "type" : "food", "item" : "bbb", "ratings" : [ 5, 9 ] }
{ "_id" : 5, "type" : "food", "item" : "aaa", "ratings" : [ 1, 2 ] }
{ "_id" : ObjectId("5d2e7c6dc5002cd792e912a9"), "type" : "food", "item" : "aaa", "ratings" : [ 7, 3 ] }

2、多键索引的一些限制

1)不能同时在两个数组字段建立复合multikey indexes

2)由于MongoDB3.6版本对排序行为上做了一些改变,导致现在对multikey index进行排序时,查询计划包括一个阻塞排序的阶段,从而对性能产生影响。在排序阻塞阶段,必须等待所有输入完成才能进行排序然后输出结果;对于一个非阻塞排序或者索引排序,sort操作只需要扫描index产生一个有序的请求。

3)多键索引不能做分片键,但是,如果一个分片是复合索引的前缀,这个复合索引支持多键索引。

4)hash索引不支持多键索引

5)多键索引不支持覆盖索引查询

6)多键索引无法使用$expr

3、多键索引是如何利用索引进行查询?

db.inventory.find( { ratings: [ 5, 9 ] } ),对于该multikey index的查询,MongoDB通过索引查找出所有包含5的记录,然后过滤出[5,9]的记录

4、Multikey Index Bounds

db.survey.insertMany([
{ _id: 1, item: "ABC", ratings: [ 2, 9 ] },
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }])

db.survey.createIndex( { ratings: 1 } )

1)Intersect Bounds


db.survey.find( { ratings : { $elemMatch: { $gte: 3, $lte: 6 } } } )

<=>     ratings: [ [ 3, 6 ] ]

执行计划:
"indexBounds" : {
                "ratings" : [
                    "[3.0, 6.0]"
                ]
            }

2)不使用 $elemMatch的情况下MongoDB不会使用multikey inedex的交集


db.survey.find( { ratings : { $gte: 3, $lte: 6 } } )

<=>     ratings: [ [ 3, Infinity ] ] or [ [ -Infinity, 6 ] ]

执行计划:
"indexBounds" : {
                "ratings" : [
                    "[-inf.0, 6.0]"
                ]
            }

3)Compound Bounds - 等值查询


db.survey.find( { item: "XYZ", ratings: { $gte: 3 } } )
db.survey.createIndex( { item: 1, ratings: 1 } )

<=>     ratings: { item: [ [ "XYZ", "XYZ" ] ], ratings: [ [ 3, Infinity ] ] }

执行计划:
"indexBounds" : {
                "item" : [
                    "[\"XYZ\", \"XYZ\"]"
                ],
                "ratings" : [
                    "[3.0, inf.0]"
                ]
            }

4)Compound Bounds - 范围查询


db.survey.find( {item: { $gte: "L", $lte: "Z"}, ratings : { $elemMatch: { $gte: 3, $lte: 6 } }} )

<=>     ratings: "item" : [ [ "L", "Z" ] ], "ratings" : [ [3.0, 6.0] ]

执行计划:
"indexBounds" : {
                "item" : [
                    "[\"L\", \"Z\"]"
                ],
                "ratings" : [
                    "[3.0, 6.0]"
                ]
            }
            

5)Compound Bounds

1.示例集合

> db.survey.insertMany([{ _id: 1, item: { name: "ABC", manufactured: 2016 }, ratings: [ 2, 9 ] }, 
{ _id: 2, item: { name: "XYZ", manufactured: 2013 },  ratings: [ 4, 3 ] }])
>
> db.survey.createIndex( { "item.name": 1, "item.manufactured": 1, ratings: 1 } )

2.查询结果

> db.survey.find( {    "item.name": "L" ,    "item.manufactured": 2012 } )

   <=>     "item.name" : [ ["L", "L"] ], "item.manufactured" : [ [2012.0, 2012.0] ]

   执行计划:
"indexBounds" : {
                "item.name" : [
                    "[\"L\", \"L\"]"
                ],
                "item.manufactured" : [
                    "[2012.0, 2012.0]"
                ],
                "ratings" : [
                    "[MinKey, MaxKey]"
                ]
            }
            
            

四、Text Indexes

示例集合

{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9904"), "song" : "1. Hotel California", "lyrics" : "On a dark desert highway, cool wind in my hair. Warm smell of colitas, rising up through the air." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9905"), "song" : "2. Hotel California", "lyrics" : "Up ahead in the distance, I saw a shimmering light. My head grew heavy and my sight grew dim." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9906"), "song" : "3. Hotel California", "lyrics" : "Such a lovely place, Such a lovely face." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9907"), "song" : "4. Hotel California", "lyrics" : "Some dance to remember, some dance to forget." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9908"), "song" : "5. Hotel California", "lyrics" : "Welcome to the Hotel California" }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9909"), "song" : "hell world", "lyrics" : "Welcome to beijing" }

1、语法

一个集合只能有一个text索引,但是该text可以是多个字段的复合索引

db.quotes.createIndex({ content : "text" })
db.reviews.createIndex({subject: "text",comments: "text"})

2、权重

1)创建全文索引默认权重为1

2)各字段的权重分布会影响到查询时的优先策略

db.blob.insertMany([{_id: 1,content: "This morning I had a cup of coffee.",about: "beverage",keywords: ["coffee"]},
{_id: 2,content: "Who doesn't like cake?",about: "food",keywords: [ "cake", "food", "dessert" ]}])

db.blog.createIndex(
   {
     content: "text",
     keywords: "text",
     about: "text"
   },
   {
     weights: {                     //执行权重
       content: 10,
       keywords: 5
     },
     name: "TextIndex"              //指定索引名字
   }
 )

3、通配符文本索引 - 表示在所有字段创建一个全文索引

db.ttlsa_com.ensureIndex({"$**": "text"})

4、复合全文索引

{ "_id" : 1, "dept" : "tech", "description" : "lime green computer" }
{ "_id" : 2, "dept" : "tech", "description" : "wireless red mouse" }
{ "_id" : 3, "dept" : "kitchen", "description" : "green placemat" }
{ "_id" : 4, "dept" : "kitchen", "description" : "red peeler" }
{ "_id" : 5, "dept" : "food", "description" : "green apple" }
{ "_id" : 6, "dept" : "food", "description" : "red potato" }

db.inventory.createIndex({dept: 1,description: "text"})

> db.inventory.find( { dept: "kitchen", $text: { $search: "green" } } )
{ "_id" : 3, "dept" : "kitchen", "description" : "green placemat" }

5、查询语法

db..find({
$text:
  {
   $search: <string>,
   $language: <string>,
   $caseSensitive: <boolean>,
   $diacriticSensitive: <boolean>
  }
})

五、2dsphere Indexes

1、2dsphere索引支持对于球体的地理位置计算

2、2dsphere索引默认为稀疏索引

如果某一文档缺少2dsphere字段(null或为空),那么该文档不会创建索引。对于一个包含其它类型的复合2dsphere索引,该文档索引的使用仅仅与2dsphere字段有关。

示例集合:

{ "_id" : ObjectId("5d2fd9a67737353186206a70"), "loc" : { "type" : "Point", "coordinates" : [ -73.97, 40.77 ] }, "name" : "Central Park", "category" : "Parks" }
{ "_id" : ObjectId("5d2fd9a67737353186206a71"), "loc" : { "type" : "Point", "coordinates" : [ -73.88, 40.78 ] }, "name" : "La Guardia Airport", "category" : "Airport" }

db.places.createIndex( { category : 1 , loc : "2dsphere" } )

> db.places.find({category:"Airport"}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.places",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "category" : {
                "$eq" : "Airport"
            }
        },
        "winningPlan" : {
            "stage" : "COLLSCAN",                       //全文档扫描
            "filter" : {
                "category" : {
                    "$eq" : "Airport"
                }
            },
            "direction" : "forward"
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "dbslave2",
        "port" : 28002,
        "version" : "4.0.10-5",
        "gitVersion" : "7dab0a3a7b7b40cf71724b5a11eff871f8c3885c"
    },
    "ok" : 1
}

3、2dsphere一些特性

1)version 2 之后,2dsphere索引支持GeoJSON格式对象写入

2)2dsphere索引没有办法作为分片键

3)2dsphere索引字段必须是坐标或者 GeoJSON 类型,否则会报错

4)2dsphere 支持 Point、MultiPoint、LineString、MultiLineString、Polygon、MultiPolygon、Geometry Collection的查询

4、创建2dsphere索引语法:

1)2dsphere索引

db.places.createIndex( { loc : "2dsphere" } )

2)复合2dsphere索引

与2d索引不同,2dsphere索引不需要将location字段放在最左前缀。

db.places.createIndex( { category : 1 , loc : "2dsphere" } )
db.places.createIndex( { loc : "2dsphere" , category : -1, name: 1 } )

5、查询语法

Polygon相关查询

1)查询指定地址位置内所有的点

语法:

db.<collection>.find( { <location field> :
    { $geoWithin :
    { $geometry :
    { type : "Polygon" ,
    coordinates : [ <coordinates> ]
} } } } )

示例:查询由coordinates指定的多边形内所有的点和形状

db.places.find( { loc :
                  { $geoWithin :
                    { $geometry :
                      { type : "Polygon" ,
                        coordinates : [ [
                                          [ 0 , 0 ] ,
                                          [ 3 , 6 ] ,
                                          [ 6 , 1 ] ,
                                          [ 0 , 0 ]
                                        ] ]
                } } } } )

2)交集

1.语法

db.<collection>.find( { <location field> :
    { $geoIntersects :
    { $geometry :
    { type : "<GeoJSON object type>" ,
    coordinates : [ <coordinates> ]
} } } } )

2.示例:查找与coordinates点组成多边形所有相交的点和形状

db.places.find( { loc :
                  { $geoIntersects :
                    { $geometry :
                      { type : "Polygon" ,
                        coordinates: [ [
                                         [ 0 , 0 ] ,
                                         [ 3 , 6 ] ,
                                         [ 6 , 1 ] ,
                                         [ 0 , 0 ]
                                       ] ]
                } } } } )
Point的点相关查询

3)临近GeoJSON Point的点

语法:

db.<collection>.find( { <location field> :
    { $near :
    { $geometry :
    { type : "Point" ,
    coordinates : [ <longitude> , <latitude> ] } ,
    $maxDistance : <distance in meters>
    } } } )

示例:

db.places.find( { loc :
                         { $near :
                           { $geometry :
                              { type : "Point" ,
                                coordinates : [ -88 , 30 ] } ,
                             $maxDistance : 3963
                      } } } )

4)指定point以及半径内所有的点

语法:

db.<collection>.find( { <location field> :
    { $geoWithin :
    { $centerSphere :
    [ [ <x>, <y> ] , <radius> ] }
} } )

示例:

db.places.find( { loc :
                  { $geoWithin :
                    { $centerSphere :
                       [ [ -88 , 30 ] , 10 / 3963.2 ]
                } } } )

六、2d Indexes

1、2d索引的一些特性

1)在MongoDB 2.2版本之前或者地址位置字段没有使用GeoJSON进行存储的情况下,我们使用2d索引比较多。

2)2d索引一般是用来计算平面上的计算,对于球面的一些几何计算,或者以GeoJSON形式来进行存储的字段,需要使用2dsphere索引

3)2d索引本质上也是一个稀疏索引

4)2d索引不支持collation选项

5)对于2d复合索引来讲,必须将2d索引字段放在复合索引最前缀

> db.places.createIndex( { state:1,"locs": "2d"} )
{
    "ok" : 0,
    "errmsg" : "2d has to be first in index",
    "code" : 16801,
    "codeName" : "Location16801"
}

2、创建语法

db.<collection>.createIndex( { <location field> : "2d" ,
    <additional field> : <value> } ,
    { <index-specification options> } )

db.collection.createIndex( { <location field> : "2d" } ,
    { min : <lower bound> , max : <upper bound> } ) //设置最大最小边界值和精度。默认情况下,最大值和最小值的范围是[ -180 , 180 ),精度是26位的精度

3、查询语法

1)查询在指定范围内所有的点 - 平面

语法:

db.<collection>.find( { <location field> :
    { $geoWithin :
    { $box|$polygon|$center : <coordinates>
} } } )

示例:

查询在[ 0 , 0 ],[ 100 , 100 ]之内的所有点:
db.places.find( { loc :
                  { $geoWithin :
                     { $box : [ [ 0 , 0 ] ,
                                [ 100 , 100 ] ]
                 } } } )
                 
查询以[-74, 40.74 ]为中心,10为半径的范围内所有的点:     
db.places.find( { loc: { $geoWithin :
                          { $center : [ [-74, 40.74 ] , 10 ]
                } } } )                 

2)查询球面中的范围查询

语法:

db.<collection>.find( { <location field> :
    { $geoWithin :
    { $centerSphere : [ [ <x>, <y> ] , <radius> ] }
} } )

示例:

db.<collection>.find( { loc : { $geoWithin :
                                 { $centerSphere :
                                    [ [ 88 , 30 ] , 10 / 3963.2 ]
                      } } } )

3)查询一个平面的临近点

语法:

db.<collection>.find( { <location field> :
    { $near : [ <x> , <y> ] }
} )

示例:

db.place.find( { loc :{ $near : [ 23 , 57 ]} } )

4)精确匹配一个点

语法:

db.<collection>.find( { loc: [ <x> , <y> ] } )

示例:

db.place.find( { loc : [ 23 , 57 ] } )

七、Hash Indexes

1、hash索引的一些特点

1)hash索引可以做分片键,这会使数据分布更加随机性

2)hash索引会通过一个hash函数来计算该文档的hash索引值,hash支持嵌套文档,但是不支持多键。

3)hash索引是由MongoDB实例来自动计算使用hash索引的,应用程序无需对其进行hash计算

2、创建hash索引语法

db.collection.createIndex( { _id: "hashed" } )

3、hash索引使用的一些限制

1)hash索引不支持创建复合索引

2)hash索引仅支持等值查询,也可以在相同的字段创建普通索引,范围查询会优先使用普通索引,等值查询优先使用hash索引。

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
2月前
|
存储 NoSQL MongoDB
掌握MongoDB索引优化策略:提升查询效率的关键
在数据库性能调优中,索引是提升查询效率的利器。本文将带你深入了解MongoDB索引的内部工作原理,探讨索引对查询性能的影响,并通过实际案例指导如何针对不同的查询模式建立有效的索引。不仅将涵盖单一字段索引,还会探讨复合索引的使用,以及如何通过分析查询模式和执行计划来优化索引,最终实现查询性能的最大化。
|
4月前
|
监控 NoSQL MongoDB
MongoDB数据库的索引管理技巧
【8月更文挑战第20天】MongoDB数据库的索引管理技巧
86 1
|
5月前
|
NoSQL Java API
MongoDB 强制使用索引 hint
MongoDB 强制使用索引 hint
157 3
|
1月前
|
存储 NoSQL 关系型数据库
MongoDB索引知识
MongoDB索引知识
32 1
MongoDB索引知识
|
6月前
|
存储 监控 NoSQL
MongoDB索引解析:工作原理、类型选择及优化策略
MongoDB索引解析:工作原理、类型选择及优化策略
|
1月前
|
存储 NoSQL MongoDB
MongoDB 索引限制
10月更文挑战第22天
45 2
|
1月前
|
NoSQL MongoDB 索引
MongoDB 高级索引
10月更文挑战第22天
36 2
|
2月前
|
NoSQL MongoDB 索引
MongoDB 覆盖索引查询
10月更文挑战第21天
36 1
|
6月前
|
NoSQL 定位技术 MongoDB
深入探索 MongoDB:高级索引解析与优化策略
深入探索 MongoDB:高级索引解析与优化策略
196 1
|
2月前
|
存储 NoSQL MongoDB
MongoDB 索引
MongoDB 索引
34 3