分布式文档存储数据库之MongoDB索引管理

  前文我们聊到了MongoDB的简介、安装和对collection的CRUD操作,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13941797.html;今天我们来聊下mongodb的索引;

  1、为什么要有索引?索引的作用是干嘛的?

  我们知道mongodb通常应用在一些web站点,数据量非常大的场景中;在大数据的场景中,对于我们要查询一个数据,mongodb是否能够快速的响应结果就变得尤为的重要;这也是索引存在的意义;索引就是用来帮助我们在很大的数据集中快速查询我们想要的数据;通常我们在mongodb中插入一条数据时,mongodb会自动给我们添加一个_id的字段,这个字段是mongodb内部自己维护,通常情况我们都不会去管它;在关系型数据库中,我们可以在单个字段上构建索引,也可以在多个字段上构建索引,之所以要在多个字段构建索引是因为我们的查询条件很可能用到的字段不只一个;所以我们构建索引的原则是根据查询条件来构建;比如我们要查询年龄大于30的用户有哪些,我们就可以把索引构建在年龄这个字段上,构建在其他字段上,对于我们要查询年龄大于30这个条件来讲是没有意义的;所以构建索引通常我们会去了解用户最常的查询,在用户最常查询的字段上构建索引,这样可以有效提高用户的查询;对于mongodb也是一样的,索引的存在就是为了提高我们的查询;

  2、为什么索引能够帮助我们快速查找呢?

  首先索引是按照我们指定的字段来构建,构建索引就是把我们指定的字段抽取出来,然后提前排好序(或者按照一定规律的方式排列好),然后保存为另外一个collection;用户在查找数据时,mongodb首先会去找索引,看看用户的条件是否和索引匹配,能够匹配,索引就能告诉用户要查询的数据在那个地方,这样就很快的找到用户查询的数据;假如我们构建的索引没有匹配用户的查询,那么用户的查询会以遍历的方式去查找,这样一来无形之中速度就变慢了(原本不加索引,直接遍历,现在有索引,要先查索引,没有命中,还要遍历);所以构建索引,如果一定是数据量很大的情况才构建,数据量小,构建索引不但不会帮助我们快速的查找内容,反而会拖慢我们的查询速度;其次在很大的数据量上,如果索引构建的字段没有被查询命中,那么我构建的索引就无意义;

  3、索引在一定程度上是要影响用户写的性能

  我们在某个字段构建好索引以后,用户在写数据时,通常会额外多一次写io;对于写请求,在没有索引的情况,用户只需要写一次io,有了索引用户每写一条数据,都会对应有一次写索引的io;这样一来在一定程度上对用户的写性能会有影响;但通常我们构建索引都是在读多写少的场景中使用;在写请求不是特别多的场景其实多一次写io,比起读请求的压力我们是可以接受的;更何况有些数据库支持延迟写索引,所谓延迟写索引是指用户在插入数据时,它不立即写索引,而是等一段时间再写,这样一来就有效的降低写索引对用户的写请求性能的影响;

  上图主要描述了索引和文档的关系,在索引里的数据通常是我们指定的字段,用特定的排列方式组织在一起,在用户查询某个数据时,就能够很快的从索引中拿到对应文档的位置,从而不用每个文档挨着遍历;这也是索引能够帮助我们快速查找的原因吧;

  4、索引类型

  索引是有类型的,不同类型的索引在内部组织索引的方式各不相同,不同类型的索引给我们查询带来的效果也不同;常见的索引类型有b+ tree(平衡树索引),hash索引、空间索引、全文索引等等;在mongodb中索引也有很多类型,不同的是我们上面说的索引类型,b+ tree,hash索引这些都是从索引内部组织结构来描述;在mongodb中的索引我们是从索引构建的位置来描述;mongodb中的索引有单键索引、组合索引、多键索引、空间索引、文本索引和hash索引;所谓单键索引是指构建在一个字段上的索引;组合索引指构建在多个字段上的索引;多键索引指将索引构建在一个键的值是一个子文档的字段上;我们知道文档和文档是可以嵌套的,这也意味着一个文档内部可以引用另一个文档,一个文档中的某个键对应的值也可以是另外一个子文档;我们把这种索引构建在一个文档中的某个键是一个子文档的某个字段上的索引叫做多键索引,它和单键索引不是对应的;空间索引指基于位置查询的索引,但通常这种索引只有用到特定的方法来查询时,它才会生效,比如使用基于空间位置的函数;文本索引指支持搜索整个文档中的文本信息,通常这种索引我们也叫全文索引;hash索引指把某个字段的值做hash计算后组织的索引;这种索引有个特点就是时间复杂度是o(1);不管数据有多少,在查找数据时所用到的时间都是一样的;之所以时间复杂度是o(1),原因是hash计算每一个值都是唯一的;这种索引的查找方式有点类似键值查找,不同的是hash背后对应的是一个hash桶,先找到hash桶,然后查找到对应的hash值;hash索引和b+树索引最大的区别是,b+树索引可以查询一个范围,因为树状索引通常是把数据组织成一个有序的结构,而hash索引不能,hash索引只能查找一个精确的值,不能查找一个范围;因为hash索引背后对应的是一个hash值,每个hash值可能都不在一个hash桶,所以我们假如要查询年龄大于30岁的用户,用hash索引就不适合,因为30和31的hash值可能就不在一个hash桶上;

  5、在mongodb数据库上创建索引

  准备数据

> use testdb
switched to db testdb
> for (i=1;i<=1000000;i++) db.peoples.insert({name:"people"+i,age:(i%120),classes:(i%20)})
WriteResult({ "nInserted" : 1 })
> db.peoples.find().count()
1000000
> db.peoples.find()
{ "_id" : ObjectId("5fa943987a7deafb9e543326"),"name" : "people1","age" : 1,"classes" : 1 }
{ "_id" : ObjectId("5fa943987a7deafb9e543327"),"name" : "people2","age" : 2,"classes" : 2 }
{ "_id" : ObjectId("5fa943987a7deafb9e543328"),"name" : "people3","age" : 3,"classes" : 3 }
{ "_id" : ObjectId("5fa943987a7deafb9e543329"),"name" : "people4","age" : 4,"classes" : 4 }
{ "_id" : ObjectId("5fa943987a7deafb9e54332a"),"name" : "people5","age" : 5,"classes" : 5 }
{ "_id" : ObjectId("5fa943987a7deafb9e54332b"),"name" : "people6","age" : 6,"classes" : 6 }
{ "_id" : ObjectId("5fa943987a7deafb9e54332c"),"name" : "people7","age" : 7,"classes" : 7 }
{ "_id" : ObjectId("5fa943987a7deafb9e54332d"),"name" : "people8","age" : 8,"classes" : 8 }
{ "_id" : ObjectId("5fa943987a7deafb9e54332e"),"name" : "people9","age" : 9,"classes" : 9 }
{ "_id" : ObjectId("5fa943987a7deafb9e54332f"),"name" : "people10","age" : 10,"classes" : 10 }
{ "_id" : ObjectId("5fa943987a7deafb9e543330"),"name" : "people11","age" : 11,"classes" : 11 }
{ "_id" : ObjectId("5fa943987a7deafb9e543331"),"name" : "people12","age" : 12,"classes" : 12 }
{ "_id" : ObjectId("5fa943987a7deafb9e543332"),"name" : "people13","age" : 13,"classes" : 13 }
{ "_id" : ObjectId("5fa943987a7deafb9e543333"),"name" : "people14","age" : 14,"classes" : 14 }
{ "_id" : ObjectId("5fa943987a7deafb9e543334"),"name" : "people15","age" : 15,"classes" : 15 }
{ "_id" : ObjectId("5fa943987a7deafb9e543335"),"name" : "people16","age" : 16,"classes" : 16 }
{ "_id" : ObjectId("5fa943987a7deafb9e543336"),"name" : "people17","age" : 17,"classes" : 17 }
{ "_id" : ObjectId("5fa943987a7deafb9e543337"),"name" : "people18","age" : 18,"classes" : 18 }
{ "_id" : ObjectId("5fa943987a7deafb9e543338"),"name" : "people19","age" : 19,"classes" : 19 }
{ "_id" : ObjectId("5fa943987a7deafb9e543339"),"name" : "people20","age" : 20,"classes" : 0 }
Type "it" for more
> it
{ "_id" : ObjectId("5fa943987a7deafb9e54333a"),"name" : "people21","age" : 21,"classes" : 1 }
{ "_id" : ObjectId("5fa943987a7deafb9e54333b"),"name" : "people22","age" : 22,"classes" : 2 }
{ "_id" : ObjectId("5fa943987a7deafb9e54333c"),"name" : "people23","age" : 23,"classes" : 3 }
{ "_id" : ObjectId("5fa943987a7deafb9e54333d"),"name" : "people24","age" : 24,"classes" : 4 }
{ "_id" : ObjectId("5fa943987a7deafb9e54333e"),"name" : "people25","age" : 25,"classes" : 5 }
{ "_id" : ObjectId("5fa943987a7deafb9e54333f"),"name" : "people26","age" : 26,"classes" : 6 }
{ "_id" : ObjectId("5fa943987a7deafb9e543340"),"name" : "people27","age" : 27,"classes" : 7 }
{ "_id" : ObjectId("5fa943987a7deafb9e543341"),"name" : "people28","age" : 28,"classes" : 8 }
{ "_id" : ObjectId("5fa943987a7deafb9e543342"),"name" : "people29","age" : 29,"classes" : 9 }
{ "_id" : ObjectId("5fa943987a7deafb9e543343"),"name" : "people30","age" : 30,"classes" : 10 }
{ "_id" : ObjectId("5fa943987a7deafb9e543344"),"name" : "people31","age" : 31,"classes" : 11 }
{ "_id" : ObjectId("5fa943987a7deafb9e543345"),"name" : "people32","age" : 32,"classes" : 12 }
{ "_id" : ObjectId("5fa943987a7deafb9e543346"),"name" : "people33","age" : 33,"classes" : 13 }
{ "_id" : ObjectId("5fa943987a7deafb9e543347"),"name" : "people34","age" : 34,"classes" : 14 }
{ "_id" : ObjectId("5fa943987a7deafb9e543348"),"name" : "people35","age" : 35,"classes" : 15 }
{ "_id" : ObjectId("5fa943987a7deafb9e543349"),"name" : "people36","age" : 36,"classes" : 16 }
{ "_id" : ObjectId("5fa943987a7deafb9e54334a"),"name" : "people37","age" : 37,"classes" : 17 }
{ "_id" : ObjectId("5fa943987a7deafb9e54334b"),"name" : "people38","age" : 38,"classes" : 18 }
{ "_id" : ObjectId("5fa943987a7deafb9e54334c"),"name" : "people39","age" : 39,"classes" : 19 }
{ "_id" : ObjectId("5fa943987a7deafb9e54334d"),"name" : "people40","age" : 40,"classes" : 0 }
Type "it" for more
> 

  提示:创建测试数据可以使用循环的方式,它这里的循环和c语言中的循环是一样的;在mongodb中查看数据,当数据量过多时,它不会一次性全部显示,而是分页显示,每次默认显示20条;键入it命令可以显示下一页;

  在mongodb上创建索引,语法格式:db.mycoll.ensureIndex(keypattern[,options])或者db.mycoll.createIndex(keypattern[,options])

  在name字段上创建索引

> db.peoples.ensureIndex({name:1})
{
        "createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1
}
> 

  提示:这里的name是指字段名称,而非索引名称;后面的1表示升序,-1表示降序;

  查看索引

> db.peoples.getIndices()
[
        {
                "v" : 2,"key" : {
                        "_id" : 1
                },"name" : "_id_"
        },{
                "v" : 2,"key" : {
                        "name" : 1
                },"name" : "name_1"
        }
]
> 

  提示:从上面返回的结果可以看到,peoples这个集合上有两个索引,一个名为_id_,其对应的字段为_id,以升序的方式排列;一个名为name_1,其对应字段为name,以升序的方式排列;默认不给索引取名,它就是字段名后面加下划线,再加表示升序或降序的数字;如下所示

  删除索引

> db.peoples.dropIndex("name_1")
{ "nIndexesWas" : 3,"ok" : 1 }
> db.peoples.dropIndex("age_-1")
{ "nIndexesWas" : 2,"ok" : 1 }
> db.peoples.getIndices()
[ { "v" : 2,"key" : { "_id" : 1 },"name" : "_id_" } ]
> 

  提示:删除索引需要指定索引名称,并且需要用引号引起来;

  在name字段上构建唯一键索引

  提示:创建唯一键索引,我们只需要在创建索引时加上unique:true这个选项即可;所谓唯一键是指我们指定的字段上的值必须是唯一的;如果在我们在插入对应字段时和之前有的数据重复,此时会插入失败;

  验证:插入一条name字段值为peoples23的数据,看看是否能够插入成功呢?

  提示:可以看到当我们在name字段上构建唯一键索引后,在插入name字段有相同值的数据时,它告诉我们说插入的数据重复;不允许我们插入;说明我们创建的唯一键索引生效了;

  重建索引

> db.peoples.reIndex()
{
        "nIndexesWas" : 2,"nIndexes" : 2,"indexes" : [
                {
                        "v" : 2,"key" : {
                                "_id" : 1
                        },"name" : "_id_"
                },{
                        "v" : 2,"unique" : true,"key" : {
                                "name" : 1
                        },"name" : "name_1"
                }
        ],"ok" : 1
}
> 

  提示:如果我们要修改索引,可以删除重新键,上面的reIndex不能实现修改原有索引的属性信息;

  构建索引并指定为后台构建,释放当前shell

> db.peoples.createIndex({age:-1},{background:true})
{
        "createdCollectionAutomatically" : false,"numIndexesBefore" : 2,"numIndexesAfter" : 3,"ok" : 1
}
> db.peoples.getIndices()
[
        {
                "v" : 2,"name" : "name_1"
        },"key" : {
                        "age" : -1
                },"name" : "age_-1","background" : true
        }
]
> 

  删除所有手动构建的索引

> db.peoples.dropIndexes()
{
        "nIndexesWas" : 3,"msg" : "non-_id indexes dropped for collection","ok" : 1
}
> db.peoples.getIndices()
[ { "v" : 2,"name" : "_id_" } ]
> 

  创建组合索引

> db.peoples.createIndex({name:1,age:1},"key" : {
                        "name" : 1,"age" : 1
                },"name" : "name_1_age_1","background" : true
        }
]
> 

  以name字段为条件查询数据,看看mongodb查询过程

> db.peoples.find({name:"people1221"}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,"namespace" : "testdb.peoples","indexFilterSet" : false,"parsedQuery" : {
                        "name" : {
                                "$eq" : "people1221"
                        }
                },"queryHash" : "01AEE5EC","planCacheKey" : "4C5AEA2C","winningPlan" : {
                        "stage" : "FETCH","inputStage" : {
                                "stage" : "IXSCAN","keyPattern" : {
                                        "name" : 1,"age" : 1
                                },"indexName" : "name_1_age_1","isMultiKey" : false,"multiKeyPaths" : {
                                        "name" : [ ],"age" : [ ]
                                },"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {
                                        "name" : [
                                                "[\"people1221\",\"people1221\"]"
                                        ],"age" : [
                                                "[MinKey,MaxKey]"
                                        ]
                                }
                        }
                },"rejectedPlans" : [ ]
        },"serverInfo" : {
                "host" : "node01.test.org","port" : 27017,"version" : "4.4.1","gitVersion" : "ad91a93a5a31e175f5cbf8c69561e788bbc55ce1"
        },"ok" : 1
}
>

  提示:从上面返回的结果可以看到在本次查询是IXSCAN(索引扫描),所以查找很快就返回了;同时也显示了索引相关的信息;

  组合name和age字段条件查询,看看是否命中索引?

> db.peoples.find({$and:[{age:{$lt:80}},{name:{$gt:"people200"}}]}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,"parsedQuery" : {
                        "$and" : [
                                {
                                        "age" : {
                                                "$lt" : 80
                                        }
                                },{
                                        "name" : {
                                                "$gt" : "people200"
                                        }
                                }
                        ]
                },"queryHash" : "96038BC4","planCacheKey" : "E71214BA","indexBounds" : {
                                        "name" : [
                                                "(\"people200\",{})"
                                        ],"age" : [
                                                "[-inf.0,80.0)"
                                        ]
                                }
                        }
                },"ok" : 1
}
>

  提示:可以看到我们组合两个字段做条件范围查询也是可以正常索引扫描;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读552次。com.mongodb.MongoQueryException: Query failed with error code 292 and error message 'Executor error during find command :: caused by :: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting.' on server 11.51.141.63:27017 _mongodb 大文件 下载失败
文章浏览阅读635次,点赞9次,收藏8次。MongoDB 是一种 NoSQL 数据库,它将每个数据存储为一个文档,这里的文档类似于 JSON/BSON 对象,具体数据结构由键值(key/value)对组成。
文章浏览阅读2.1k次。和。_mongodb 日期类型
文章浏览阅读1.7k次。Scalestack等客户期待使用MongoDB Atlas Vector Search和Amazon Bedrock构建下一代应用程序
文章浏览阅读970次。SpringBoot整合中间件mongodb、ES_springboot3 elasticsearch json数据
文章浏览阅读673次。MongoDB 简介_尚医通sql
文章浏览阅读1k次,点赞8次,收藏9次。官网下载MongoDB安装包后进行解压(因了解并不深入,故暂不进行详细说明,自行查找其他安装方法,后期了解深入后将进行该教程的完善)在bin目录下使用命令启动:./mongod --config …/mongodb.conf。该文章任然处于完善中,如果存在错误遗漏的地方,欢迎私信联系。安装相关的nuget包后即可通过以下方法连接数据。YX9010_0@的第二十篇文章。
文章浏览阅读1.2k次,点赞17次,收藏26次。社交场景, 使用 MongoDB 存储存储用户信息, 以及用户发表的朋友圈信息, 通过地理位置索引实现附近的人, 地点等功能.游戏场景, 使用 MongoDB 存储游戏用户信息, 用户的装备, 积分等直接以内嵌文档的形式存储, 方便查询, 高效率存储和访问.物流场景, 使用 MongoDB 存储订单信息, 订单状态在运送过程中会不断更新, 以 MongoDB 内嵌数组的形式来存储, 一次查询就能将订单所有的变更读取出来.物联网场景, 使用 MongoDB 存储所有接入的智能设备信息, 以及设备汇报的日
文章浏览阅读686次。您可以使用 update_one() 方法来更新 MongoDB 中调用的记录或文档。update_one() 方法的第一个参数是 query 对象,用于定义要更新的文档。注释:如果查询找到多个记录,则仅更新第一个匹配项。第二个参数是定义文档新值的对象。_python 更新 mongodb 数据
文章浏览阅读1.3k次。首先来学习一下nosql这里安装就不进行介绍 只记录一下让自己了解mongodb。_nosql注入
文章浏览阅读4.1k次,点赞8次,收藏7次。在data的目录下,创建一个db文件。因为启动MongoDB服务之前必须创建数据库文件的存放文件夹,否则命令不会自动创建,而且不能启动成功。第一步:安装时,Custom是指可以自定义安装路径,然后傻瓜式安装即可(注意:先不要安装图形化工具,否则安装时间会特别长):如果要想连接成功,必须要开服务,即mongod -dbpath C:MongoDBdatadb的cmd要一直开着。然后回车,ctrl+F输入port找到端口号,一般为:27017。打开命令行,然后找到bin文件地址,并输入。_mongodb windows安装
文章浏览阅读5.1k次,点赞3次,收藏43次。详细介绍MongoDB数据库的基本知识,安装方法,基本操作,_mongodb数据库
文章浏览阅读3.2k次。安装教程翻看以往文章。_navicat 连接mongodb
文章浏览阅读426次,点赞9次,收藏12次。win10开放端口:https://blog.csdn.net/m0_43605481/article/details/119255256。我的是阿里云服务器,所以直接在安全组中加入规则,端口范围:27017,授权对象:0.0.0.0。windows在mongodb安装文件夹的bin文件夹中的mongod.cfg。数据库名字是test,打算创建一个用户,账号aaa,密码bbb,权限readWrite。因为该用户是创建在test数据库的,所以在最后要加上test。O了,然后恢复了test的数据。
文章浏览阅读1.1k次。聚合操作主要用于处理数据并返回计算结果。聚合操作将来自多个文档的值组合在一起,按条件分组后,再进行一系列操作(如求和、平均值、最大值、最小值)以返回单个结果。MongoDB的聚合查询​聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的在单个文档里不存在的文档信息。MongoDB中聚合(aggregate)主要用于处理数据(例如分组统计平均值、求和、最大值等),并返回计算后的数据结果,有点类似sql语句中的count(*)、groupby。..._如何将几个db的数据统整在一起做查询
文章浏览阅读680次,点赞7次,收藏8次。(2)application.properties配置文件。(4)UserService类。(5)测试和测试结果。
文章浏览阅读1k次,点赞17次,收藏25次。Studio 3T 2023.9 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端,支持自然语言查询_mongodb客户端
文章浏览阅读1.1k次,点赞32次,收藏27次。插件式的存储引擎架构可以实现 Server 层和存储引擎层的解耦,可以支持多种存储引擎,如 MySQL 既可以支持 B-Tree 结构的 InnoDB 存储引擎,还可以支持 LSM 结构的 RocksDB 存储引擎。MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。的简称,是 JSON 文档的二进制表示,支持将文档和数组嵌入到其他文档和数组中,还包含允许表示不属于 JSON 规范的数据类型的扩展。
文章浏览阅读5.1k次,点赞6次,收藏96次。本文设计了一种基于智能室内温度控制的自动调速风扇。以STM32系列单片机为核心主控板,通过程序代码驱动和使用温度传感器模块实现对环境温度的实时监测,并可以实时显示环境温度。同时,可以设置温度检测的上下警告值,根据需求自行调节。_stm32 温控风扇
文章浏览阅读898次,点赞13次,收藏21次。在MongoDB中,我们使用find()和find_one()方法来在集合中查找数据,就像在MySQL数据库中使用SELECT语句来在表中查找数据一样。_pymongo find_one