索引及索引限制

索引及索引限制

一.使用索引

1.单一字段(键)索引

语法:db.collection_name.createIndex({:})

> use test
switched to db test
> db.books.find()
{ "_id" : ObjectId("5e0cb711eb18ea3208bc19a8"), "name" : "C语言编程", "price" : 32
}
{ "_id" : ObjectId("5e0cb746eb18ea3208bc19a9"), "name" : "Python入门", "price" :
48 }
{ "_id" : ObjectId("5e0cb8e0eb18ea3208bc19aa"), "name" : "Java学习", "price" : 65
}
{ "_id" : ObjectId("5e0cbbd2eb18ea3208bc19b7"), "name" : "小学生教材", "price" :
20 }
{ "_id" : ObjectId("5e0cbbd2eb18ea3208bc19b8"), "name" : "初中生教材", "price" :
30 }
{ "_id" : ObjectId("5e0cbbd2eb18ea3208bc19b9"), "name" : "高中生教材", "price" :
40 }
{ "_id" : ObjectId("5e0cbc16eb18ea3208bc19ba"), "name" : "英文教材", "price" : 49
}
> db.books.createIndex({name:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.books.find({name:{$regex:/教材$/}})
{ "_id" : ObjectId("5e0cbbd2eb18ea3208bc19b8"), "name" : "初中生教材", "price" :
30 }
{ "_id" : ObjectId("5e0cbbd2eb18ea3208bc19b7"), "name" : "小学生教材", "price" :
20 }
{ "_id" : ObjectId("5e0cbc16eb18ea3208bc19ba"), "name" : "英文教材", "price" : 49
}
{ "_id" : ObjectId("5e0cbbd2eb18ea3208bc19b9"), "name" : "高中生教材", "price" :
40 }
> db.books.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.books"
},
{
"v" : 2,
"key" : {
"name" : 1
},
"name" : "name_1",
"ns" : "test.books"
}
]

2.字段值唯一索引

语法:db.collection_name.createIndex({ : },{unique:true})

> db.books.createIndex({price:1},{unique:true})
{
	"createdCollectionAutomatically" : true,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}

3.多字段索引

语法:db.collection_name.createIndex({ : , : })

db.foo.insert( [ {name:"《a cat 故事》",price:20,color:"red"}, {name:"《crying brids故事》",price:20,color:"green"},  {name:"《big Dogs故事》",price:25,color:"blue"} ] )
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 3,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
> db.foo.find()
{ "_id" : ObjectId("6274a6327ba4c1a412060b0f"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("6274b5d1f81e82b239821b79"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("6274bb6ca530d1d413596095"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("6279adc1e36cad4f83df195e"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("627afe03dc33bf23d007892c"), "name" : "《a cat 故事》", "price" : 20, "color" : "red" }
{ "_id" : ObjectId("627afe03dc33bf23d007892d"), "name" : "《crying brids故事》", "price" : 20, "color" : "green" }
{ "_id" : ObjectId("627afe03dc33bf23d007892e"), "name" : "《big Dogs故事》", "price" : 25, "color" : "blue" }
> db.foo.createIndex(
... {price:1,color:-1}
... )
{
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}
#使用find()查找文档记录,然后对结果用sort派粗查询,先对price做升序,在price价格一样的情况下再做color降序排序
> db.foo.find({},{_id:0}).sort({price:1,color:-1})
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "name" : "《a cat 故事》", "price" : 20, "color" : "red" }
{ "name" : "《crying brids故事》", "price" : 20, "color" : "green" }
{ "name" : "《big Dogs故事》", "price" : 25, "color" : "blue" }
#用sort组price降序排序,color升序排序
> db.foo.find({},{_id:0}).sort({price:-1,color:1})
{ "name" : "《big Dogs故事》", "price" : 25, "color" : "blue" }
{ "name" : "《crying brids故事》", "price" : 20, "color" : "green" }
{ "name" : "《a cat 故事》", "price" : 20, "color" : "red" }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
#用sort组price升序排序,color升序排序
> db.foo.find({},{_id:0}).sort({price:1,color:1})
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 1 }
{ "name" : "《crying brids故事》", "price" : 20, "color" : "green" }
{ "name" : "《a cat 故事》", "price" : 20, "color" : "red" }
{ "name" : "《big Dogs故事》", "price" : 25, "color" : "blue" }
多字段唯一索引
> db.foo.createIndex({name:1,price:1},{unique:true})
{
        "ok" : 0,
        "errmsg" : "Index build failed: 7617cb93-a4d4-42ea-822f-1a935675ba9b: Collection test.foo ( 8f40f73c-3789-4bbb-b3d7-d539c1b586de ) :: caused by :: E11000 duplicate key error collection: test.foo index: name_1_price_1 dup key: { name: null, price: null }",
        "code" : 11000,
        "codeName" : "DuplicateKey",
        "keyPattern" : {
                "name" : 1,
                "price" : 1
        },
        "keyValue" : {
                "name" : null,
                "price" : null
        }
}

4.文本索引

语法:db.collection_name.createIndex({:“text”,:“text”,…})

> db.books.createIndex({name:"text"})
{
        "numIndexesBefore" : 3,
        "numIndexesAfter" : 4,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}
**通配符文本索引
> db.books.createIndex({"$**":"text"})
{
        "ok" : 0,
        "errmsg" : "An equivalent index already exists with a different name and options. Requested index: { v: 2, key: { _fts: \"text\", _ftsx: 1 }, name: \"$**_text\", weights: { $**: 1 }, default_language: \"english\", language_override: \"language\", textIndexVersion: 3 }, existing index: { v: 2, key: { _fts: \"text\", _ftsx: 1 }, name: \"name_text\", weights: { name: 1 }, default_language: \"english\", language_override: \"language\", textIndexVersion: 3 }",
        "code" : 85,
        "codeName" : "IndexOptionsConflict"
}

5.哈希索引

语法:db.collection_name.createIndex({key:“hashed”})

> db.foo.createIndex({_id:"hashed"})
{
        "numIndexesBefore" : 3,
        "numIndexesAfter" : 3,
        "note" : "all indexes already exist",
        "ok" : 1
}

6.ensureIndex()索引

语法:db.collection_name.ensureIndex({:n,:n,…},option)

早期的MongoDB索引命令 MongoDB 3.0开始用createIndex命令代替ensureIndex。已经过期被淘汰的

7.与索引相关的其他方法

db.collection.dropIndex(index):移除集合指定的索引功能。index参数为指定需要删除的集合索 引名,可用getIndexes()函数获取集合的所有索引名称。

db.collection.dropIndexes():移除一个集合的所有索引功能。

db.colleciton.getIndexes():返回一个指定集合的现有索引描述信息的文档数组。

db.collection.reIndex():删除指定集合上所有索引,并重新构建所有现有索引。在具有大量数据 集合的情况下,该操作将大量消耗服务器的运行资源,引起运行性能急剧下降等问题的发生。

db.collection.totalIndexSize():提供指定集合索引大小的报告信息。

二.高级索引

1.子文档索引

语法:db.collection_name.createIndex({:,:,…})

> use eshops
switched to db eshops
> db.books.insert(
... [
... {name:"《生活百科故事1》",price:50,summary:{kind:"学前",content:"1-7岁用"}},
... {name:"《生活百科故事2》",price:50,summary:{kind:"少儿",content:"8-16岁用"}}
... ])
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 2,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
#对一个子文档的两个键的值进行索引。1位升序,-1为降序。
> db.books.createIndex( { "summary.kind":1,"summary.content":-1 } )
{
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}
> db.books.find({"summary.kind":"少儿"}).pretty()
{
        "_id" : ObjectId("627b05fcdc33bf23d0078930"),
        "name" : "《生活百科故事2》",
        "price" : 50,
        "summary" : {
                "kind" : "少儿",
                "content" : "8-16岁用"
        }
}

2.数组索引

语法:db.collection_name.createIndex({:,:,…})

#插入两个带数组的文档
> db.books.insert(
... [
... {
... name:"《e故事》",
... price:30,
... tags:[{no:1,press:"x出版社"},{no:2,press:"y出版社"},{no:3,press:"z出版社"}]
... },
... {
... name:"《f故事》",
... price:30,
... tags:[{no:11,press:"x出版社"},{no:4,press:"y出版社"},{no:2,press:"z出版社"}]
... }
... ]
)
#对一个数组的两个键的值进行索引。1位升序、-1位降序
> db.books.createIndex(
... { "tags.no":1,"tags.press":-1}
... )
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
> db.books.find({"tags.no":2}).pretty()
{
"_id" : ObjectId("5e2ff4989581899dc57c2981"),
"name" : "《e故事》",
"price" : 30,
"tags" : [
{
"no" : 1,
"press" : "x出版社"
},
{
"no" : 2,
"press" : "y出版社"
},
{
"no" : 3,
"press" : "z出版社"
}
]
}
{
"_id" : ObjectId("5e2ff4989581899dc57c2982"),
"name" : "《f故事》",
"price" : 30,
"tags" : [
{
"no" : 11,
"press" : "x出版社"
},
{
"no" : 4,
"press" : "y出版社"
},
{
"no" : 2,
"press" : "z出版社"
}
]
}

3.2dsphere(地理空间索引)

语法:db.collection_name.createIndex({:“2dsphere”})

#插入一条地理空间属性文档数据
> db.places.insert(
... {
... location:{type:"Point",coordinates:[ -29.32, 50.11 ]},
... name: "北海公园",
... category:"公园"
... }
... )
WriteResult({ "nInserted" : 1 })
#建立2dsphere索引
> db.places.createIndex({location:"2dsphere"})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.places.find( { location: { $near:{$geometry:{type: "Point",coordinates:[-29,49]},$maxDistance:200000} } } ).pretty()
{
"_id" : ObjectId("5e2ff7f29581899dc57c2983"),
"location" : {
"type" : "Point",
"coordinates" : [
-29.32,
50.11
]
},
"name" : "北海公园",
"category" : "公园"
}

三.索引限制

1.索引额外开销

建立一个索引至少需要8KB的数据存储空间,也就是索引是需要消耗内存和磁盘的存储空间的。 另外,对集合做插入、更新和删除时,若相关字段建立了索引,同步也会引起对索引内容的更新操作 (锁独占排他性操作),这个过程是影响数据库的读写性能的,有时甚至会比较严重。所以,如果业务 系统所使用的集合很少对集合进行读取操作,则建议不使用索引。

2.内存使用限制

索引在使用时,是驻内存中持续运行的,所以索引大小不能超过内存的限制。MongoDB在索引大小超 过内存限制范围后,将会删除一些索引,这将导致系统运行性能下降。索引占用空间大小,可以通过 db.collection_name.totalIndexSize()方法来获取。

3.查询限制

索引不能被以下的查询使用:

正则表达式及非操作符,如 n i n 、 nin、 ninnot等

算术运算符,如$mod等

$where子句

说明:

​ 查询语句能否使用索引功能,可以用find()的explain()来查看

​ 对重要的集合进行索引查询操作,使用前建议进行严格的模拟测试

4.索引最大范围 集

集合中的索引不能超过64个;索引名的长度不能超过125个字符;一个多值索引最多可以有31个字段。 如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。

5.不应该使用索引场景

使用索引是否合适,主要看查询操作的使用场景,预先进行模拟测试非常重要。

​ 如果查询要返回的结果超过集合文档记录的1/3,那么是否建立索引,需要慎 重考虑;

​ 对于以写为主的集合,建议慎用索引,默认情况下_id够用了。

查询高级分析

Explain()分析

1.Explain()命令格式

语法:db.Collection.Command().explain(modes)

2.Explain()执行返回结果及分析

> use test
switched to db test
> db.books.find().explain("executionStats")
{
        "explainVersion" : "1",
        "queryPlanner" : {
                "namespace" : "test.books",
                "indexFilterSet" : false,
                "parsedQuery" : {

                },
                "maxIndexedOrSolutionsReached" : false,
                "maxIndexedAndSolutionsReached" : false,
                "maxScansToExplodeReached" : false,
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 7,
                "executionTimeMillis" : 1,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 7,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "nReturned" : 7,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 9,
                        "advanced" : 7,
                        "needTime" : 1,
                        "needYield" : 0,
                        "saveState" : 0,
                        "restoreState" : 0,
                        "isEOF" : 1,
                        "direction" : "forward",
                        "docsExamined" : 7
                }
        },
        "command" : {
                "find" : "books",
                "filter" : {

                },
                "$db" : "test"
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "5.0.8",
                "gitVersion" : "c87e1c23421bf79614baf500fda6622bd90f674e"
        },
        "serverParameters" : {
                "internalQueryFacetBufferSizeBytes" : 104857600,
                "internalQueryFacetMaxOutputDocSizeBytes" : 104857600,
                "internalLookupStageIntermediateDocumentMaxSizeBytes" : 104857600,
                "internalDocumentSourceGroupMaxMemoryBytes" : 104857600,
                "internalQueryMaxBlockingSortMemoryUsageBytes" : 104857600,
                "internalQueryProhibitBlockingMergeOnMongoS" : 0,
                "internalQueryMaxAddToSetBytes" : 104857600,
                "internalDocumentSourceSetWindowFieldsMaxMemoryBytes" : 104857600
        },
        "ok" : 1
}

主要参数:

1.winningPlan.stage:最佳的计划阶段,其值为(含子阶段值):

​ SINGLE_SHARD:单一分片操作

​ SHARD_MERGE:多分片合并操作

​ IXSCAN:带索引查询

​ COLLSCAN:集合扫描。在处理海量数据时,尽量避免出现这种执行方式。因 为集合扫描过 程比较低效,甚至影响系统的运行性能。

​ AND_HASH:带哈希索引的操作

​ OR:索引操作的条件里带“$or”表达式

​ SHARDING_FILTER:分片索引

​ SORT:在内存中进行了排序,在处理大规模数据时,需要慎重考虑是否需要 这样做,因为它 消耗内存,影响系统运行性能

​ LIMIT:使用limit()命令限制返回数

​ SKIP:使用skip()进行跳过

​ IDHACK:针对_id进行查询

​ COUNT:使用count()进行了查询

​ TEXT:使用全文索引进行查询

​ COUNT_SCAN:查询时使用Index进行count()。

2.shardName:分片名,如“shard003”。

3.connectionString:分片所在的服务器地址,如“localhost:27023”。

4.serverInfo:服务器相关的信息,如host、port等

5.namespace:find()数据库空间,包含了数据库名和集合名

6.indexFilterSet:代表find()运行时,是否使用了带索引key条件

7.parsedQuery:解析查询条件,如" e q " : 1 、 " eq":1、" eq":1"and":[]等

8.inputStage:嵌套文档操作类型

9.rejectedPlans:查询优化器考虑和拒绝的候选计划数组,如果没有候选计划,数组为空。

上述参数内容,在Explain()为“queryPlanner”模式下类似。下面为executionStats模式下的新增统计内容:

  1. nReturned:返回符合查询条件的文档数;
  2. executionTimeMillis:查询计划选择和查询执行所需的总时间(单位:毫秒),该时间越小,系统 响应越快,若超过2、3秒就应该引起重视;
  3. totalKeysExamined:扫描的索引条目数量;扫描索引条目的数量越少越好;
  4. totalDocsExamined:扫描文档的数量;越少越好
  5. executionStages.works:查询工作单元数,一个查询执行可以将其工作分成若干个小单元,如检 查单个索引字、从集合中获取单个文档,将投影应用于单个文档等;
  6. executionStages.advanced:优先返回的结果数目;
  7. executionStages.needTime:在子阶段,执行未优化的操作过程所需要的时间;
  8. executionStages.needYield:数据库查询时,产生的锁的次数;次数越少越好,越多说明查询性 能存在问题,并发查询冲突等问题严重;
  9. executionStages.isEOF:指定执行阶段是否结束,如果结束该值为true或1;如果没有结束该值为 false或0。
  10. executionStages.invalidates:执行字阶段无效的数量。

3.Hint()分析

db.users.find().hint({KaTeX parse error: Expected 'EOF', got '}' at position 10: natural:1}̲) //强制执行正向扫描 db…natural:-1}) //强制执行反向扫描

> use eshops
switched to db eshops
> db.books.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        {
                "v" : 2,
                "key" : {
                        "summary.kind" : 1,
                        "summary.content" : -1
                },
                "name" : "summary.kind_1_summary.content_-1"
        },
        {
                "v" : 2,
                "key" : {
                        "tags.no" : 1,
                        "tags.press" : -1
                },
                "name" : "tags.no_1_tags.press_-1"
        }
]

#在hint()强制执行基于_id正向扫描时,其执行结果Explain()主要时间参数如下:

> db.books.find({"summary.kind":"少儿"}).hint({_id:1}).explain("executionStats")
{
#省略部分内容
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 15,
"totalKeysExamined" : 4,
"totalDocsExamined" : 4,
#省略部分内容
}

在没有强制指定索引方式时,其执行结果Explain()主要时间参数如下:

> db.books.find({"summary.kind":"少儿"}).explain("executionStats")
{
#省略部分内容
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 12,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
#省略部分内容
}

两次虽然在总用时时间上差不多,但是在查找执行过程中,在强制方式下扫描了4个索引对象,并检查了 4个文档;在没有强制方式下,只扫描了一个索引对象,一个文档;这在大数据环境下,后者效率要高很 多。

可视化管理工具

MongoDB支持好多可视化管理工具:

​ Robomongo 管理工具

​ Rockmongo

​ Mongo Vue

​ Ops 管理工具(MongoDB Ops Manager)

​ Compass数据浏览和分析工具

​ Cloud管理工具(MongoDB Cloud Manager)

Robomongo

  1. 免费且开源,官方下载地址:https://robomongo.org/download

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmNZMIXk-1652235940310)(https://p1.xywm.ltd/2022/05/11/627b1d4b243bb.png)]

2.安装后建立连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2O7aVvwe-1652235940311)(https://p1.xywm.ltd/2022/05/11/627b1d7572d45.png)]

3.建立连接后既可以进行操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n9y6s2a6-1652235940312)(https://p1.xywm.ltd/2022/05/11/627b1dab464d1.png)]

“nReturned” : 1,
“executionTimeMillis” : 12,
“totalKeysExamined” : 1,
“totalDocsExamined” : 1,
#省略部分内容
}


两次虽然在总用时时间上差不多,但是在查找执行过程中,在强制方式下扫描了4个索引对象,并检查了 4个文档;在没有强制方式下,只扫描了一个索引对象,一个文档;这在大数据环境下,后者效率要高很 多。

# **可视化管理工具**

MongoDB支持好多可视化管理工具:

​		Robomongo 管理工具 

​		Rockmongo 

​		Mongo Vue 

​		Ops 管理工具(MongoDB Ops Manager) 

​		Compass数据浏览和分析工具 

​		Cloud管理工具(MongoDB Cloud Manager)

## **Robomongo**

1. 免费且开源,官方下载地址:https://robomongo.org/download

[外链图片转存中...(img-wmNZMIXk-1652235940310)]

2.安装后建立连接

[外链图片转存中...(img-2O7aVvwe-1652235940311)]

3.建立连接后既可以进行操作

[外链图片转存中...(img-n9y6s2a6-1652235940312)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值