🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[toc] ## 索引 索引 字段较少 且是有序的 索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构 特殊的数据结构,按顺序保存文档中的一个或多个字段 ### ensureIndex({xx:1}) #### 默认行为 ![](https://box.kancloud.cn/33a9ebdd00f969d24f33f7218dfa1fdf_442x168.png) 默认系统会自动帮我们创建一个`_id`的索引 ![](https://box.kancloud.cn/7a7615cdcf159bb72e115e826f2208ef_322x320.png) 1是升序,-1是降序 ![](https://box.kancloud.cn/4b5c1c1fdc7212c746e7d8183560e858_282x58.png) 当我们创建索引时弱没有取名字,系统会自动生成,比如你建了一个索引叫`xx` 会自动生成索引名字叫`xx_1`(升序) or `xx_-1`(降序) #### 具名索引 也可以自己生成一个索引名 ``` db.students.ensureIndex({name:1},{name:'namedIndex'}); ``` ![](https://box.kancloud.cn/46f198de84c7348152b621064a911320_332x438.png) #### unique 以下栗子中id这个字段的值在每个文档中不可重复 ![](https://box.kancloud.cn/580d20bc7bc579eb54b8ce090963293e_493x42.png) ##### 创建唯一索引并删除重复记录 dropDups,貌似新版mongoDB中已废弃 ``` db.person.ensureIndex({ "name" : -1 },{ "name" : "indexname", "unique" : true,dropDups:true }) ``` #### 支持对数组类型的值的key进行索引 ``` db.students.insert({hobby:['basketball','football','pingpang']}); db.students.ensureIndex({hobby:1}); db.students.find({hobby:'football'},{hobby:1,_id:0}).explain(true); ``` #### 在后台创建索引 默认索引创建时是阻断用户继续输入的命令的 ``` db.students.ensureIndex({name:1},{name:'nameIndex',unique:true,background:true}); ``` #### 过期索引 过期过后,下一次跑任务的时候才会删掉 ``` db.stus.insert({time:new Date()}); db.stus.ensureIndex({time:1},{expireAfterSeconds:10}); db.stus.find(); ``` 1. 索引字段的值必须Date对象,不能是其它类型比如时间戳 2. 删除时间不精确,每60秒跑一次。删除也要时间,所以有误差。 #### 复合索引 查询的条件不止一个,需要用复合索引 ``` db.students.ensureIndex({name:1,age:1}); db.students.find({name:1,age:2},{name:1,age:1,_id:0}).explain(true); ``` #### 全文索引 大篇幅的文章中搜索关键词,MongoDB为我们提供了全文索引 假若我们有以下数据 ``` db.article.insert({content:'I am a gir'}); db.article.insert({content:'I am a boy'}); ``` 首先添加索引(开启全文检索) ![](https://box.kancloud.cn/be9f2f4673bb8600ce2ddff2cb03959e_420x118.png) - $text:表示要在全文索引中查东西 - $search:后边跟查找的内容, 默认全部匹配 ``` db.article.find({$text:{$search:'boy'}}); db.article.find({$text:{$search:'girl'}}); db.article.find({$text:{$search:'boy girl'}});//多次查找,多个关键字为或的关系 db.article.find({$text:{$search:"a b"}}); db.article.find({$text:{$search:"boy -girl"}}); // -表示取消 db.article.find({$text:{$search:"a \"coco cola\" b "}}); //支持转义符的,用\斜杠来转义 ``` 其中`\"coco cola\"`表示一个整体 #### 二维索引 ![](https://box.kancloud.cn/a564d64f5f7736d5c551633d05b54c32_222x220.png) ``` db.maps.ensureIndex({gis:'2d'},{min:1,max:3}); 默认会创建一个2D索引 ``` ![](https://box.kancloud.cn/a7a7b3dc6c9e68a677225e45db677b56_405x234.png) ##### 查询处理点x最近的n个点 ``` db.maps.find({gis:{$near:[1,1]}}).limit(3); ``` ![](https://box.kancloud.cn/65d6ed1ca382c5b454781dbd7d775369_536x73.png) ##### 查询以点()和()为对角线的正方形的所有点 ``` db.map.find({gis:{$within:{$box:[[1,1],[2,2]]}}},{_id:0,gis:1}); ``` ![](https://box.kancloud.cn/eaa83f7988b3e0f3e478858ab5b9cf34_537x85.png) ##### 查出以圆心 ``` db.maps.find({gis:{$within:{$center:[[2,2],1]}}},{_id:0,gis:1}); ``` ### dropIndex() ![](https://box.kancloud.cn/ed01eb4796d710c28543eaf46ab9248c_365x32.png) ### 索引使用的注意事项 - 1为正序 -1为倒序 - 索引虽然可以提升查询性能,但会降低插件性能,对于插入多查询少不要创索引 - 数据量不大时不需要使用索引。性能的提升并不明显,反而大大增加了内存和硬盘的消耗。 - 查询数据超过表数据量30%时,不要使用索引字段查询 - 排序工作的时候可以建立索引以提高排序速度 - 数字索引,要比字符串索引快的多 ## 监控查询过程 MongoDB 提供了一个 explain 命令让我们获知系统如何处理查询请求。利用 explain 命令,我们可以很好地观察系统如何使用索引来加快检索,同时可以针对性优化索引。 将`explain`置为`true` ``` db.students.find({age:299999}).explain(true); ``` - cursor: 返回游标类型 - BasicCursor而没有使用索引的查询并不是胡乱查询,而是使用了基本游标:,同理, - 使用索引的查询就是BtreeCursor - nscanned: 查找过的索引条目的数量 - n: 返回的文档数量 - nscannedObjects :数据库按照索引去磁盘上查找实际文档的次数 - millis: 执行本次查询所花费的时间,以毫秒计算,这也是判断查询效率的一个重点 - indexBounds: 描述索引的使用情况 - isMultiKey:是否使用了多键索引 - scanAndOrder: 是否在内存中对结果进行了排序 - indexOnly:是否仅仅使用索引完成了本次查询 --- queryPlanner分析 - queryPlanner: queryPlanner的返回 - queryPlanner.namespace:该值返回的是该query所查询的表 - queryPlanner.indexFilterSet:针对该query是否有indexfilter - queryPlanner.winningPlan:查询优化器针对该query所返回的最优执行计划的详细内容。 - queryPlanner.winningPlan.stage:最优执行计划的stage,这里返回是FETCH,可以理解为通过返回的index位置去检索具体的文档(stage有数个模式,将在后文中进行详解)。 - queryPlanner.winningPlan.inputStage:用来描述子stage,并且为其父stage提供文档和索引关键字。 - queryPlanner.winningPlan.stage的child stage,此处是IXSCAN,表示进行的是index scanning。 - queryPlanner.winningPlan.keyPattern:所扫描的index内容,此处是did:1,status:1,modify_time: -1与scid : 1 - queryPlanner.winningPlan.indexName:winning plan所选用的index。 - queryPlanner.winningPlan.isMultiKey是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。 - queryPlanner.winningPlan.direction:此query的查询顺序,此处是forward,如果用了.sort({modify_time:-1})将显示backward。 - queryPlanner.winningPlan.indexBounds:winningplan所扫描的索引范围,如果没有制定范围就是[MaxKey, MinKey],这主要是直接定位到mongodb的chunck中去查找数据,加快数据读取。 - queryPlanner.rejectedPlans:其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同,故不在此赘述。 --- 对executionStats返回逐层分析 - 第一层,executionTimeMillis - 最为直观explain返回值是executionTimeMillis值,指的是我们这条语句的执行时间,这个值当然是希望越少越好。 - 其中有3个executionTimeMillis,分别是: - executionStats.executionTimeMillis 该query的整体查询时间。 - executionStats.executionStages.executionTimeMillisEstimate - 该查询根据index去检索document获得2001条数据的时间。 - executionStats.executionStages.inputStage.executionTimeMillisEstimate - 该查询扫描2001行index所用时间。 - 第二层,index与document扫描数与查询返回条目数 这个主要讨论3个返回项,nReturned、totalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描条目。 这些都是直观地影响到executionTimeMillis,我们需要扫描的越少速度越快。 对于一个查询,我们最理想的状态是:nReturned=totalKeysExamined=totalDocsExamined - 第三层,stage状态分析 那么又是什么影响到了totalKeysExamined和totalDocsExamined?是stage的类型。类型列举如下: - COLLSCAN:全表扫描 - IXSCAN:索引扫描 - FETCH:根据索引去检索指定document - SHARD_MERGE:将各个分片返回数据进行merge - SORT:表明在内存中进行了排序 - LIMIT:使用limit限制返回数 - SKIP:使用skip进行跳过 - IDHACK:针对_id进行查询 - SHARDING_FILTER:通过mongos对分片数据进行查询 - COUNT:利用db.coll.explain().count()之类进行count运算 - COUNTSCAN:count不使用Index进行count时的stage返回 - COUNT_SCAN:count使用了Index进行count时的stage返回 - SUBPLA:未使用到索引的$or查询的stage返回 - TEXT:使用全文索引进行查询时候的stage返回 - PROJECTION:限定返回字段时候stage的返回 - 对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引): - Fetch+IDHACK - Fetch+ixscan - Limit+(Fetch+ixscan) - PROJECTION+ixscan - SHARDING_FITER+ixscan - COUNT_SCAN - 不希望看到包含如下的stage: - COLLSCAN(全表扫描),SORT(使用sort但是无index),不合理的SKIP,SUBPLA(未用到index的$or),COUNTSCAN(不使用index进行count) ## 配置主从服务器 ``` master.conf ``` ![](https://box.kancloud.cn/3a98f4d88e586ca263dd90a8d7e44d7b_254x115.png) ``` slave.conf ``` ![](https://box.kancloud.cn/13c24bb501f6ff7ef0a6da96ebcd9344_208x117.png) 默认情况下只有主服务器才能读 ![](https://box.kancloud.cn/7fe5b1ebd2c850540462805259b23c4e_417x173.png) 或则可以输入命令`rs.slaveOk()` ![](https://box.kancloud.cn/1eeaebeaa795311cf0e736ab06f7b61b_566x110.png) 弊端:不能自主切换 ### 主从复制的其它设置项 - -only 从节点-> 指定复制某个数据库默认是复制全部数据库 - -slavedelay 从节点-> 设置主数据库同步数据的延迟(单位是秒) - -fastsync 从节点-> 以主数据库的节点快照为节点启动从数据库 有可能从服务器不是一开始就加入的而是后面才加入的,主服务器上已经有数据了,这时我们可以给主服务器拍个快照,强行把缓存区内容写入到硬盘上然后同步到从服务器上 - -autoresync 从节点->如果不同步则重新同步数据库 - -oplogSize 主节点->设置oplog的大小(主节点操作记录存储到local的oplog中) ![](https://box.kancloud.cn/5a287e98578a78e80ffed5f3dc7d6494_285x133.png) ### 查看从服务器数据来源 ![](https://box.kancloud.cn/a053cee94ec8f72c714b0e4c9c767848_668x63.png) ### 删除添加从服务器数据来源 ![](https://box.kancloud.cn/71375765eb6389e72cb550979ad76a69_270x48.png) ![](https://box.kancloud.cn/87d0726c83c46d1113927955f1146704_393x47.png) ## 副本集 ### 运行流程 - 一台活跃服务器和二个备份服务器 - 当活跃服务器出现故障,这时集群根据权重算法推选出出活跃服务器 - 当原来的主服务器恢复后又会变成从服务器 ### 配置副本集 A服务器 ``` dbpath=E:\repl\repl1 port=2001 replSet=group ``` B服务器 ``` dbpath=E:\repl\repl2 port=2002 replSet=group ``` C服务器 ``` dbpath=E:\repl\repl3 port=2003 replSet=group ``` >**注意:** `replSet`设置了值一样才能作为一个副本集存在,设置了相同值的副本集为同一个`group` 依次按配置文件启动服务器 ### 初始化副本集 - rs.initiate() 启动一个新的副本集 - rs.conf() 查看副本集的配置 - rs.status() 命令 启动服务器后,我们还不知道我们的小伙伴具体是谁,要配置一下(随便链接一个服务器) ![](https://box.kancloud.cn/cdd9e4626e031a6476611b513be59ec4_377x179.png) ![](https://box.kancloud.cn/9d728b1d3fa44442d1080743ce6224da_607x234.png) >**注意:** 不是PRIMARY 就是 SECONDARY 么有THIDARY什么的 当PRIMARY挂掉后,其它副本集会选举出一个新的`PRIMARY`,注意,当原本的primary重连后会成为secondary ### 高级参数 - standard 常规节点 参与投票有可能成为活跃节点 - passive 副本节点 参与投票,但不能成为活跃节点 - arbiter 仲裁节点 只参与投票,不复制节点,也不能成为活跃节点 - priority 0到1000之间,0代表是副本节点,1到1000是常规节点 - arbiterOnly:true 仲裁节点 ### 读写分离操作 一般情况下作为副本节点是不能进行数据库操作的,但是在读取密集的系统中读写分离是必要的 ### Oplog 它被存储在本地数据库local中,会记录每一个操作。 如果希望在故障恢复的时候尽可能更多,可以把这个size设置的大一点 默认5% disk ``` --oplogSize 1024 use local; db.oplog.rs.find().limit(2); ``` ## 官方文档 - [点我](https://docs.mongodb.com/manual/reference/configuration-options/)