聊聊非关系型数据库MongoDB索引

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: 聊聊非关系型数据库MongoDB索引


今天是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…


我们经常在集合上创建索引的时候会碰到上面那个错误,原因就是我们集合里面已经有了重复的数据。

碰到这种情况,通常的方式是

  1. 先找出重复的数据进行清理掉,再重建(线上),比如通过聚合
  2. 使用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})

这种方式虽然会消耗比较长的时间,但是不会锁定数据库,从而保证其他操作的运行。

同样在数据量小的集合的副本级上面我们也能这样做,在主节点上建立索引,然后同步到备份节点上面。

但是在数据量大的集合我们需要拆分每个节点来进行建立索引,避免索引期间所有副本级无法正常工作,导致出现问题。

拆分从节点建立索引步骤如下:

  1. 关闭一个从节点A,独立启动
  2. 在这个从节点A建立索引
  3. 重新将A加入副本级
  4. 重复上面三个步奏

对于主节点我们可以进行故障转移为从节点或者直接进行建立索引(对性能有一定影响),通过上面的方式就能大大提高我们建立索引安全稳定性。

我曾经就碰到过有同学没有拆分执行就建立索引的情况,导致几台DB节点打满,无法工作,大家需要注意下,如果由于环境因素做不到,那么我们需要找DB空闲时间进行上述操作。


何时用索引?

虽然绝大多数场景,我们都必须要有索引才能提高效率。

但有时候我们需要考虑是否真的有必要使用索引,因为使用索引需要进行两次查找,一次查找索引条目,一次根据索引指针查找相应的文档,而全表扫描只需要一次查找过程。

下面我们来对比一下,索引适用与不适用情况。

image.png

图片从上面图我们知道索引适合,集合大,文档大,选择性查询情况,不适合与之相反的集合小,文档小,非选择性查询的情况。


几点建议

关于索引的一些建议:

  • 学会使用explain进行分析,对比索引和非索引区别,检索条数,消耗毫秒数等
  • 关注读写比率,因为如果应用写多读少 ,添加索引会影响写入性能
  • 在索引基数高的地方建立索引(比如邮箱,用户名,而不是性别)
  • $or 查询是两次独立查询拼接而成,效率没有使用 $IN的高
  • $ne 或者 $nin 操作在索引上是无效的
  • 设计多个字段索引时,先用精确匹配查询,然后再用范围匹配(比如y>10&&y<100)的字段




相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
打赏
0
0
0
0
3
分享
相关文章
微服务——MongoDB常用命令——MongoDB索引知识概述
本文介绍MongoDB索引相关知识,包括其在查询中的重要作用。索引可避免全集合扫描,显著提升查询效率,尤其在处理海量数据时。通过B树数据结构存储字段值并排序,支持相等匹配、范围查询及排序操作。文中还提供了官方文档链接以供深入学习。
70 0
数据库主键与索引详解
本文介绍了主键与索引的核心特性及其区别。主键具有唯一标识、数量限制、存储类型和自动排序等特点,用于确保数据完整性和提升查询效率;而索引通过特殊数据结构(如B+树、哈希)优化查询速度,适用于不同场景。文章分析了主键与索引的优劣、适用场景及工作原理,并对比两者在唯一性、数量限制、功能定位等方面的差异,为数据库设计提供指导。
微服务——MongoDB常用命令——MongoDB索引的类型
本节介绍了MongoDB中索引的几种类型及其特点。包括单字段索引,支持升序/降序排序,索引顺序对操作无影响;复合索引,字段顺序重要,可实现多级排序;地理空间索引,支持平面与球面几何查询;文本索引,用于字符串搜索并存储词根;哈希索引,基于字段值散列,适合等值匹配但不支持范围查询。
132 1
微服务——MongoDB常用命令——MongoDB索引的类型
数据库数据恢复——MongoDB数据库服务无法启动的数据恢复案例
MongoDB数据库数据恢复环境: 一台Windows Server操作系统虚拟机上部署MongoDB数据库。 MongoDB数据库故障: 管理员在未关闭MongoDB服务的情况下拷贝数据库文件。将MongoDB数据库文件拷贝到其他分区后,对MongoDB数据库所在原分区进行了格式化操作。格式化完成后将数据库文件拷回原分区,并重新启动MongoDB服务。发现服务无法启动并报错。
MongoDB索引知识
MongoDB索引是提升查询性能的关键工具,通过构建特殊的数据结构(如B树)优化数据访问路径。无索引时,查询需全集合扫描,时间复杂度为O(n);使用索引后可降至O(log n),实现毫秒级响应。MongoDB支持多种索引类型:单字段索引适用于高频单字段查询;复合索引基于最左前缀原则优化多条件过滤和排序;专业索引包括地理空间索引(支持LBS服务)、文本索引(全文搜索)和哈希索引(分片键优化)。合理选择和优化索引类型,可显著提升数据库性能。建议使用explain()分析查询计划,并定期清理冗余索引。
数据库索引采用B+树不采用B树的原因?
● B+树更便于遍历:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。 ● B+树的磁盘读写代价更低:B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。 ● B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条
微服务——MongoDB常用命令1——数据库操作
本节介绍了 MongoDB 中数据库的选择、创建与删除操作。使用 `use 数据库名称` 可选择或创建数据库,若数据库不存在则自动创建。通过 `show dbs` 或 `show databases` 查看所有可访问的数据库,用 `db` 命令查看当前数据库。注意,集合仅在插入数据后才会真正创建。数据库命名需遵循 UTF-8 格式,避免特殊字符,长度不超过 64 字节,且部分名称如 `admin`、`local` 和 `config` 为系统保留。删除数据库可通过 `db.dropDatabase()` 实现,主要用于移除已持久化的数据库。
186 0
从 MongoDB 到 时序数据库 TDengine,沃太能源实现 18 倍写入性能提升
沃太能源是国内领先储能设备生产厂商,数十万储能终端遍布世界各地。此前使用 MongoDB 存储时序数据,但随着设备测点增加,MongoDB 在存储效率、写入性能、查询性能等方面暴露出短板。经过对比,沃太能源选择了专业时序数据库 TDengine,生产效能显著提升:整体上,数据压缩率超 10 倍、写入性能提升 18 倍,查询在特定场景上也实现了数倍的提升。同时减少了技术架构复杂度,实现了零代码数据接入。本文将对 TDengine 在沃太能源的应用情况进行详解。
183 0
数据库数据恢复—MongoDB数据库迁移过程中丢失文件的数据恢复案例
某单位一台MongoDB数据库由于业务需求进行了数据迁移,数据库迁移后提示:“Windows无法启动MongoDB服务(位于 本地计算机 上)错误1067:进程意外终止。”
如何使用列索引一键加速慢查询?PolarDB AutoIndex大揭秘
如何使用列索引一键加速慢查询?PolarDB AutoIndex大揭秘

热门文章

最新文章

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等