内容简介:今天是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 增量索引模拟实时索引
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Everything Store
Brad Stone / Little, Brown and Company / 2013-10-22 / USD 28.00
The definitive story of Amazon.com, one of the most successful companies in the world, and of its driven, brilliant founder, Jeff Bezos. Amazon.com started off delivering books through the mail. Bu......一起来看看 《The Everything Store》 这本书的介绍吧!