内容简介:今天是1024程序员节和大家简单聊下Mongo数据库的索引。Mongo索引是基于B-tree,存储在一个易于遍历读取的数据集合中,它是对数据库表中一列或多列的值进行排序的一种结构。数据库的索引和我们书籍目录相似,有了索引,我们不需要翻阅整本书,只需要查看目录就知道我们要的内容在哪儿,并且直接定位到,这种方式能大大提高我们的查找效率。
今天是1024 程序员 节和大家简单聊下Mongo数据库的索引。
Mongo索引是基于B-tree,存储在一个易于遍历读取的数据集合中,它是对数据库表中一列或多列的值进行 排序 的一种结构。
数据库的索引和我们书籍目录相似,有了索引,我们不需要翻阅整本书,只需要查看目录就知道我们要的内容在哪儿,并且直接定位到,这种方式能大大提高我们的查找效率。
聚个例子
为了让大家更直观了解,我基于mongo3.6简单插入了1百万条数据进去,通过explain来进行分析查询情况。
scanv_rs:PRIMARY> db.users.count() 1000000 scanv_rs:PRIMARY> db.users.ensureIndex({"username": 1}) 创建索引之后 scanv_rs:PRIMARY> db.users.find({"username": 'user10001'}).explain() { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.users", "indexFilterSet" : false, "parsedQuery" : { "username" : { "$eq" : "user10001" } }, "winningPlan" : { "stage" : "FETCH", # 通过返回index位置检索文档 "inputStage" : { "stage" : "IXSCAN", # 索引查找,没有建立索引就是COLLSCAN "keyPattern" : { "username" : 1 }, "indexName" : "username_1", # 索引名字 "isMultiKey" : false, # 建立在数组上,这儿是true "multiKeyPaths" : { "username" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "username" : [ "[\"user10001\", \"user10001\"]" ] } } }, "rejectedPlans" : [ ] }, } } 有部分删减 scanv_rs:PRIMARY>db.users.find({"username":'user10001'}).explain('executionStats') 复制代码
这里就不进一步展示了。 上面最后语句执行的结果这里就不展示了,结果就是在1000000条数据,"executionTimeMillis" 字段值建立前花费1450ms,建立后花费2ms, 相差百倍,totalDocsExamined 一个建立索引前全文扫描1000000条,建立后只有1条。
大家有兴趣可以自行对比一下。从上面我们可以看到索引的威力。
索引有哪几种?
简单说完索引之后,我们再来聊下索引的分类,索引主要分为:唯一索引和稀疏索引。
唯一索引可以确保集合的每一个文档的指定健都有唯一值。
举个例子,我们要在集合里面建立username索引,通过这种方式可以确保username在不同的文档里面拥有的username是唯一的(其实我们常用_id索引也是唯一索引)
db.yourcollection.ensureIndex({"username":1}, {"unique": true})
如果在上面的集合中添加相同username数据就会导致失败 E11000 dumplicate key error…
我们经常在集合上创建索引的时候会碰到上面那个错误,原因就是我们集合里面已经有了重复的数据。
碰到这种情况,通常的方式是
先找出重复的数据进行清理掉,再重建(线上),比如通过聚合
使用dropDups简单粗暴处理
通过dropDups的方式,在创建索引的时候加上,可以强制性建立唯一索引,遇到重复的值,第一个保留,其他进行删掉。
db.yourcollection.ensureIndex({"username":1}, {"unique": true, "dropDups": true})
第二种方式通常用在开发测试环境中,线上环境请注意。
说完唯一索引,我们再来了解下稀疏索引。
由于唯一索引会把null看做值,所以无法将多个缺少唯一索引中的健的文档插入到集合中。
这个时候我们可以通过创建稀疏索引的方式来进行,一个值可存在可不存在,如果存在就必须是唯一的。我们只需要添加一个spare选项就能创建稀疏索引。
比如我们要建立一个可选的姓名,如果提供了姓名,那么它的值必须是唯一的。
db.yourcollection.ensureIndex({'username': 1}, {'unique': true, 'sparse': true})
上面是单一健索引,其实我们还有基于多个健的复合索引,全文索引,地理空间索引,由于篇幅有限,这里面我们就先不深入进去。
怎么建立索引?
介绍分类之后,我们聊聊怎么建立索引,新建索引是一件费时费资源的事情,默认情况索引创建会阻塞对数据库的读写请求,一直到索引创建完成。
如果希望创建所以任然能处理读写请求,创建时我们需要指定background参数。
比如在单机服务器上我们可以加上background 为True。
db.yourcollection.ensureIndex({'username': 1}, {background: true})
这种方式虽然会消耗比较长的时间,但是不会锁定数据库,从而保证其他操作的运行。
同样在数据量小的集合的副本级上面我们也能这样做,在主节点上建立索引,然后同步到备份节点上面。
但是在数据量大的集合我们需要拆分每个节点来进行建立索引,避免索引期间所有副本级无法正常工作,导致出现问题。
拆分从节点建立索引步骤如下:
-
关闭一个从节点A,独立启动
-
在这个从节点A建立索引
-
重新将A加入副本级
-
重复上面三个步奏
对于主节点我们可以进行故障转移为从节点或者直接进行建立索引(对性能有一定影响),通过上面的方式就能大大提高我们建立索引安全稳定性。
我曾经就碰到过有同学没有拆分执行就建立索引的情况,导致几台DB节点打满,无法工作,大家需要注意下,如果由于环境因素做不到,那么我们需要找DB空闲时间进行上述操作。
何时用索引?
虽然绝大多数场景,我们都必须要有索引才能提高效率。
但有时候我们需要考虑是否真的有必要使用索引,因为使用索引需要进行两次查找,一次查找索引条目,一次根据索引指针查找相应的文档,而全表扫描只需要一次查找过程。
下面我们来对比一下,索引适用与不适用情况。
从上面图我们知道索引适合,集合大,文档大,选择性查询情况,不适合与之相反的集合小,文档小,非选择性查询的情况。
以上所述就是小编给大家介绍的《聊聊非关系型数据库MongoDB索引》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 简单的聊聊索引的那些事儿
- 聊聊 MySQL 索引和 Redis 跳表
- MySQL索引使用说明(单列索引和多列索引)
- Elasticsearch索引的基本操作(3)-索引的滚动索引
- Coreseek 增量索引模拟实时索引
- Coreseek 增量索引模拟实时索引
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
图论算法理论、实现及应用
王桂平//王衍//任嘉辰 / 北京大学 / 2011-1 / 54.00元
《图论算法理论、实现及应用》系统地介绍了图论算法理论,并选取经典的ACM/ICPC竞赛题目为例题阐述图论算法思想,侧重于图论算法的程序实现及应用。《图论算法理论、实现及应用》第1章介绍图的基本概念和图的两种存储表示方法:邻接矩阵和邻接表,第2~9章分别讨论图的遍历与活动网络问题,树与图的生成树,最短路径问题,可行遍性问题,网络流问题,支配集、覆盖集、独立集与匹配,图的连通性问题,平面图及图的着色问......一起来看看 《图论算法理论、实现及应用》 这本书的介绍吧!