MongoDB系列之一文总结索引

概述

分类

索引的分类:

  • 按照索引包含的字段数量,可分为单键索引(单字段索引)和组合索引(联合索引、复合索引)
  • 按照索引字段的类型,可以分为主键索引和非主键索引
  • 按照索引节点与物理记录的对应方式来分,可以分为聚簇索引和非聚簇索引,其中聚簇索引是指索引节点上直接包含了数据记录,而后者则仅仅包含一个指向数据记录的指针
  • 按照索引的特性不同,可分为唯一索引、稀疏索引、文本索引、地理空间索引等

索引介绍

单键索引和复合索引

创建单键索引:db.user.ensureIndex({ income: 1});

单字段索引对内嵌字段创建索引:db.user.ensureIndex({ health.height: 1}); // 健康指标信息

创建复合索引:db.user.ensureIndex({ income: 1, health.height: 1});

数组索引

数组索引,也被称为多值索引(multikey index),当对数组型的字段创建索引时,这个索引就是多值的。多值索引在使用上与普通索引并没有什么不同,只是在索引键上会同时产生多个值。数组索引必然会使索引的条目和体积发生膨胀。

多值索引和复合索引可以一起使用,即复合索引前面的字段是非数组类型,后面的字段是数组类型(这个先后顺序,和关系型数据库组合索引最左匹配原则是一个意思)。MongoDB不支持一个复合索引中同时出现多个多值索引,即不允许出现多个数组类型字段。

db.user.ensureIndex({ age: 1, hobbies: 1}); // OK, 可以有多个爱好
db.user.ensureIndex({ hobbies: 1, careers: 1}); // wrong, 职业经历(生涯)

地理空间索引

LBS,Location Based Service,基于地理位置的检索。

2dsphere

MongoDB有两种类型的地理空间索引:2dsphere和2d。2dsphere索引可以与基于WGS84基准的地球球面几何模型一起使用。这个基准将地球表面模拟成一个扁圆球体,这意味着在两极会比较扁。使用 2dsphere 索引的距离计算考虑到地球的形状,提供比2d索引更准确的距离处理,如计算两个城市之间的距离。在存储二维平面上的点时使用2d索引。

2dsphere允许以GeoJSON格式指定点、线和多边形。点由一个二元数组给出,[经度,纬度],即[longitude,latitude]。GeoJSON格式是固定的:

"location" : {"type" : "Point","coordinates" : [50, 2]
}

即type和coordinates两个字段名不能更改,type枚举值有:Point、LineString、Polygon。location可以使用其他名称,如loc。

创建一个地理空间索引:db.shop.createIndex({ loc: "2dsphere"})。可使用三种类型的地理空间查询:交集(intersection)、包含(within)和接近(nearness)。

查询:

db.shop.find({loc: {$near: {$geometry: {type: Point, coordinates: [121.615, 31.190] } },$maxDistance: 1000,}
})

$near操作符,用于实现附近店铺的检索,返回数据结果会按距离排序。$geometry操作符用于指定一个GeoJSON格式的地理空间对象,type=Point表示地理坐标点,coordinates则是用户当前所在的经纬度位置;$maxDistance限定最大距离,单位是米。

注意点:

  • MongoDB的地理空间检索基于WGS84坐标系,在与一些地图平台集成时需要注意转换,如GCJ-02(火星坐标系)、BD-09(百度中国坐标系)
  • MongoDB 4.0版本之后,near可以用于分片集合(sharded collection),而在此版本之前可以使用geoNear聚合操作来代替

2d

对于非球面地图(电子游戏地图、时间序列数据等),可使用2d索引代替2dsphere索引:db.game.createIndex({ 'tile': '2d' }, );

默认情况下,2d 索引会假设取值范围为-180到180。如果希望对边界大小进行调整,则可以指定最小值和最大值作为createIndex的选项:db.game.ensureIndex({ 'tile': '2d'}, {min: -1000, max: 1000});

2d索引支持$geoWithin$nearSphere$near查询选择器。

应该使用 $geoWithin查询在平面上定义的形状内的点。$geoWithin可以查询矩形、多边形、圆形或球体内的所有点,它使用$geometry运算符来指定 GeoJSON 对象。

db.game.find({tile: {$geoWithin: {$box: [[0, 0], [10, 10]]}}}); // 查询左下角为[0, 0]、右上角为[10, 10]的矩形内的文档,即坐标
db.game.find({tile: {$geoWithin: {$center: [[0, 0], 5]}}}); // 查询圆心为[0, 0]、半径为5的圆形内的坐标
db.game.find({tile: {$geoWithin: {$polygon: [[0, 0], [3, 6], [3, 0]]}}}); // 查询三个点指定的三角形(多边形)内的所有文档

由于历史遗留原因,MongoDB支持在平面2d索引上执行球面查询,结合$geoWithin$centerSphere运算符。指定一个数组,其中包括圆心坐标和以弧度为单位的圆半径:db.game.find({tile: {$geoWithin: {$centerSphere: [[0, 0], 0.01]}}});

临近查询会返回距离给定点最近的坐标对的文档,并按照距离对结果进行排序:db.game.find({tile: {$near: [0, 0]}});

全文搜索索引

MongoDB Atlas全文搜索索引(full-text search index)基于Apache Lucene。

MongoDB text索引支持全文搜索,不同于精确匹配搜索、模糊搜索、正则表达式搜索。text索引需要一定数量的与被索引字段中单词成比例的键。创建text索引可能会消耗大量的系统资源。有分片时,则还会减慢数据移动的速度:当迁移到一个新分片时,所有文本都必须重新进行索引。

创建全文索引:

db.articles.createIndex(
{"title": "text", "body": "text"},
{"weights" : {"title" : 3, "body" : 2}}
)

全文索引中的字段顺序并不重要,等同对待。如果要区别对待,可通过weights对每个字段指定权重来控制不同字段的相对重要性。索引一旦创建,就不能改变字段的权重,除非删除索引再重建。

对于某些集合,如果不知道文档包含哪个字段。可以使用$**在文档的所有字符串字段上创建全文本索引。这样做不仅会对顶层的字符串字段建立索引,也会搜索内嵌文档和数组中的字符串字段。

文本索引存在诸多限制,如并未提供中文分词功能,应用场景有限。

TTL索引

并非所有的数据都需要持久化存储,即过了一定时间段后,可以执行硬删除,如监控业务日志。TTL索引对于此场景提供支持。

TTL索引需要声明在一个日期类型的字段上:db.sysLog.ensureIndex({ 'createDate': 1}, { expireAfterSeconds: 3600 });。为systemlog集合声明一个TTL索引,指向createdDate字段,expireAfterSeconds=3600表示数据将在createdDate之后3600秒(1小时)后过期。

MongoDB会在周期性运行的后台线程中对该集合进行检查及数据清理工作。TTL索引具有普通索引的功能,同样可以用于加速数据的查询。

修改TTL索引过期时间:db.runCommand({collMod: 'sysLog', index: {keyPattern: {createDate: 1}, expireAfterSeconds: 7200 }});

需要注意以下限制:

  • 只能支持单个字段,且必须是非_id字段
  • TTL索引不能用于固定集合
  • TTL索引无法保证及时的数据老化,MongoDB会通过后台的TTL Monitor定时器来清理老化数据,典型的间隔时间是1分钟。当然如果在数据库负载过高的情况下,TTL的行为则会进一步受到影响
  • TTL索引对于数据的清理仅仅使用remove命令,并不是很高效。TTL Monitor在运行期间对系统CPU、磁盘都会造成一定的压力。相比之下,按日期分表的方式操作会更加高效

条件索引

partial index,条件索引允许只对部分文档建立索引。

db.book.createIndex({ 'name': 1}, { partialFilterExpression: {rateing: {$gt: 8 } } });

上面的SQL对书籍评分超过8分的文档才创建索引。

稀疏索引

模糊索引

索引特性

唯一性索引

通过unique=true选项可将索引定义为唯一性索引:db.user.ensureIndex({ name: 1 }, { unique: true });

也可用于复合索引:db.book.ensureIndex({ type: 1, title: 1}, { unique: true }); // 分类下的书籍标题保持唯一性

也可用于嵌套文档::db.user.ensureIndex({ 'health.height': 1}, { unique: true });

嵌套文档的唯一性约束根据不同的MongoDB版本,其行为不太一致。以6.0.5版本来说,字段的位置无所谓,MongoDB会识别出来:
在这里插入图片描述
对数组索引使用唯一性约束,可以保证所有的文档之间不会存在重叠的数组元素:db.user.ensureIndex({ 'careers': 1}, { unique: true });。数组索引上的唯一性约束并无法保证同一个文档中包含重复的元素。需要从应用层进行distinct去重处理,如使用Set集合。

db.user.insertOne({careers: ['DevOps', 'IT manager']});
db.user.insertOne({careers: ['doctor', 'nurse', 'doctor']});

注意事项:

  • 唯一性索引对于文档中缺失的字段,会使用null值代替,因此不允许存在多个文档缺失索引字段的情况。

集合现在有2条数据:
在这里插入图片描述
对一个新增字段创建索引:db.user.ensureIndex({ 'health.height': 1}, { unique: true });,报错:Write failed with error code 11000 and error message 'Index build failed: caused by :: E11000 duplicate key error collection: test.user index: health.height_1 dup key: { health.height: null }'

  • 对于分片的集合,唯一性约束必须匹配分片规则。换句话说,为了保证全局的唯一性,分片键必须作为唯一性索引的前缀字段。

ensureIndex和createIndex

进阶

explain

和关系型数据库一样,MongoDB也提供explain命令帮助评估指定查询模型(query model)的计划。

命令db.getSiblingDB("corpus").getCollection('mds_factors').find().explain('executionStats');执行输出:

[{"$clusterTime": {"clusterTime": {"$timestamp": {"t": 1706014465, "i": 1}},"signature": {"hash": {"$binary": {"base64": "ZFjBv3to5hMaqrdVckd9c0qZh7M=", "subType": "00"}},"keyId": 7281537397286764545}},"executionStats": {"executionSuccess": true,"nReturned": 1,"executionTimeMillis": 5,"totalKeysExamined": 1,"totalDocsExamined": 1,"executionStages": {"stage": "FETCH","nReturned": 1,"executionTimeMillisEstimate": 0,"works": 2,"advanced": 1,"needTime": 0,"needYield": 0,"saveState": 0,"restoreState": 0,"isEOF": 1,"invalidates": 0,"docsExamined": 1,"alreadyHasObj": 0,"inputStage": {"stage": "IXSCAN","nReturned": 1,"executionTimeMillisEstimate": 0,"works": 2,"advanced": 1,"needTime": 0,"needYield": 0,"saveState": 0,"restoreState": 0,"isEOF": 1,"invalidates": 0,"keyPattern": {"key": 1},"indexName": "key","isMultiKey": false,"multiKeyPaths": {"key": []},"isUnique": false,"isSparse": false,"isPartial": false,"indexVersion": 2,"direction": "forward","indexBounds": {"key": ["[\"factor:Age\", \"factor:Age\"]"]},"keysExamined": 1,"seeks": 1,"dupsTested": 0,"dupsDropped": 0,"seenInvalidated": 0}}},"ok": 1,"operationTime": {"$timestamp": {"t": 1706014465, "i": 1}},"queryPlanner": {"plannerVersion": 1,"namespace": "corpus.mds_factors","indexFilterSet": false,"parsedQuery": {"key": {"$eq": "factor:Age"}},"winningPlan": {"stage": "FETCH","inputStage": {"stage": "IXSCAN","keyPattern": {"key": 1},"indexName": "key","isMultiKey": false,"multiKeyPaths": {"key": []},"isUnique": false,"isSparse": false,"isPartial": false,"indexVersion": 2,"direction": "forward","indexBounds": {"key": ["[\"factor:Age\", \"factor:Age\"]"]}}},"rejectedPlans": []},"serverInfo": {"host": "mongodb-replicaset-2","port": 27017,"version": "3.6.20","gitVersion": "39c200878284912f19553901a6fea4b31531a899"}}
]

解读:

  • winningPlan:表示获胜的计划,即数据库经过一系列评估后选择的最优计划,stage=COLLSCAN表示全表扫描,IXSCAN表示索引扫描
  • executionStats:描述执行的过程信息。nReturned指返回结果条数,而totalDocsExamined表明整个过程扫描多少条记录

参考

  • MongoDB进阶与实战:微服务整合、性能优化、架构管理
  • MongoDB权威指南
  • difference-between-createindex-and-ensureindex-in-java-using-mongodb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/642406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NQA网络质量分析

概念 网络质量分析是设备上集成网络测试功能,不仅可以实现对网络运行情况的准确测试,还可以输出统计信息,有效的节约成本。 NQA可以检测网络上运行的各种协议的性能,使运营商能够实时采集到各种网络运行指标。 例如:HTTP的总时延、TCP连接时延、DNS解析时延、文件传输速…

行测-判断:2.类比推理

行测-判断:2.类比推理 给出一组相关的词,要求通过观察分析,在备选答案中找出一组与之在逻辑关系上最为贴近或相似的词。 1. 语义关系★★ 1.1 近义关系,反义关系 C,反义词 B,BD 都是近义词,考…

如何用Python常用魔术方法阅读源码?13组代码轻松了解!

在看 python 源码的过程中我们会经常看到一些特殊方法,也就是双下划线方法。其实双下划线方法是特殊方法,是由 python 解释器提供的具有特殊意义的方法,主要是 python 源码程序员使用的,我们在开发中尽量不要使用双下方法&#xf…

Element中的el-input-number+SpringBoot+mysql

1、编写模板 <el-form ref"form" label-width"100px"><el-form-item label"商品id&#xff1a;"><el-input v-model"id" disabled></el-input></el-form-item><el-form-item label"商品名称&a…

java抽象工厂实战与总结

文章目录 一、工厂模式&#xff08;三种&#xff09;1.简单工厂模式1.1 概念&#xff1a;1.2 使用场景&#xff1a;1.3 模型图解&#xff1a;1.4 伪代码&#xff1a; 2.工厂方法模式2.1 概念&#xff1a;2.2 使用场景&#xff1a;2.3 模型图解&#xff1a;2.4 伪代码 3.抽象工厂…

用户反映在浏览器中使用AI工具 Copilot 遇到严重卡顿问题,微软官方给出初步解释

近日&#xff0c;多位用户反馈在使用Edge和Chrome浏览器中的Copilot时出现卡顿问题&#xff0c;甚至需要重启浏览器才能解决。对此&#xff0c;微软广告和网络服务部门CEO米哈伊尔帕拉欣表示&#xff0c;问题可能与Edge浏览器的“效率模式”有关。 微软中国官方网址链接&#x…

黑马——Java学生管理系统

一、学生管理系统 学生管理系统 需求&#xff1a; 采取控制台的方式去书写学生管理系统。 loop:while(true){ for(){ break loop;//给while循环取名loop&#xff0c;break loop;可以跳出while循环 } } 或者使用System.exit(0);停止虚拟机运行&#xff0c;相当于让所有代码停…

【表情识别阅读笔记】Towards Semi-Supervised Deep FER with An Adaptive Confidence Margin

论文名&#xff1a; Towards Semi-Supervised Deep Facial Expression Recognition with An Adaptive Confidence Margin 论文来源&#xff1a; CVPR 发表时间&#xff1a; 2022-04 研究背景&#xff1a; 对大量图片或视频进行手工标注表情是一件极其繁琐的事情&#xff0c;因此…

Python 自动化办公:一键批量生成 PPT

Stata and Python 数据分析 一、导读 在实际工作中&#xff0c;经常需要批量处理Office文件&#xff0c;比如需要制作一个几十页的PPT进行产品介绍时&#xff0c;一页一页地制作不仅麻烦而且格式可能不统一。那么有什么办法可以一键生成PPT呢&#xff1f;Python提供的pptx 包…

05章【面向对象(下)】

文章目录 继承继承的基本概念继承的限制继承小结子类的实例化过程方法的重写super关键字继承的应用示例final关键字 抽象类接口多态性instanceof关键字抽象类和接口的应用抽象类应用—模板方法模式接口应用—策略模式 Object类模式简单工厂模式静态代理模式适配器模式 内部类数…

策略模式【结合Spring框架实践】

Hello!~大家好啊,很高兴我们又见面了,今天我们一起学习设计模式–【策略模式】 初次对此模式不懂的,或者想偷懒的,我强烈建议大家跟着我的一起把概念和代码一起敲一遍!~为啥子??因为我就是这样学会的,哈哈哈! 1.首先我们看下此模式的整体UML图 selector:选择器又叫做上下文co…

Netty篇章(1)—— 核心原理介绍

终于进入到Netty框架的环节了&#xff0c;前面介绍了大量的Java-NIO的内容&#xff0c;核心的内容Selector、Channel、Buffer、Reactor掌握了&#xff0c;那么学起来Netty也是水到渠成的事情。如果没有掌握前面的内容那么学Netty会非常吃力&#xff0c;下面讲解Netty核心原理与…

关于 LLM,你了解多少?

LLM定义 大语言模型&#xff08;LLM&#xff09;是一种基于大量文本数据训练的深度学习模型。它的主要功能是生成自然语言文本或理解语言文本的含义。这些模型可以处理多种自然语言任务&#xff0c;如文本分类、问答、对话等&#xff0c;是通向人工智能的一条重要途径。 LLM发…

美创荣登“2023大数据产业年度最具投资价值”榜单

近日&#xff0c;由上海市经济和信息化委员会、上海市科学技术委员会指导&#xff0c;数据猿和上海大数据联盟主办的“第六届金猿季&魔方论坛——大数据产业发展论坛”在沪隆重召开&#xff0c;并重磅揭晓《2023大数据产业年度最具投资价值》榜单。 美创科技凭借在数据安全…

k8s-kubectl常用命令

一、基础命令 1.1 get 查询集群所有资源的详细信息&#xff0c;resource包括集群节点、运行的Pod、Deployment、Service等。 1.1.1 查询Pod kubectl get po -o wid 1.1.2 查询所有NameSpace kubectl get namespace 1.1.3 查询NameSpace下Pod kubectl get po --all-namespaces…

JAVA 学习 面试(二)多线程篇

Java多线程 线程池 线程池原理 创建方式&#xff1a;newFixedThreadPool (固定数目线程的线程池)、newCachedThreadPool(可缓存线程的线程池)、newSingleThreadExecutor(单线程的线程池)、newScheduledThreadPool(定时及周期执行的线程池)、new ThreadPoolExecutor() &#x…

Elasticsearch 常用信息

简述 本文针对 Elasticsearch&#xff08;简称ES&#xff09;集群6.x版本出现故障时&#xff0c;可通过提供的命令进行排查。 1、集群健康状态 集群健康状态状态说明red不是所有的主要分片都可用。表示该集群中存在不可用的主分片。可以理解为某个或者某几个索引存在主分片丢失…

AI破局之路:一名猎头高管的AI自学之旅——公众号

AI破局之路&#xff1a;一名猎头高管的AI自学之旅——公众号。 我是周知&#xff0c;有8年猎头行业经验深耕各类顶级科技企业。 2023年&#xff0c;应该有很多同行离开这个行业吧. 毕竟我们面临着前所未有的挑战。猎头行业的每一个参与者&#xff0c;无论是初入职场的猎头新人、…

2024最新科普:文件加密软件功能大盘点

随着信息化时代的到来&#xff0c;数据安全问题越来越受到人们的关注。 文件加密作为一种重要的数据保护手段&#xff0c;被广泛应用于企业和个人用户中。 本文将对文件加密软件的功能进行大盘点&#xff0c;帮助大家了解这一安全领域的知识。 一、文件加密软件的定义 文件加…

【STM32】USB程序烧录需要重新上电 软件复位方法

文章目录 一、问题二、解决思路2.1 直接插拔USB2.2 给芯片复位 三、解决方法3.1 别人的解决方法3.2 在下载界面进行设置 一、问题 最近学习STM32的USB功能&#xff0c;主要是想要使用虚拟串口功能&#xff08;VCP&#xff09;&#xff0c;发现每次烧录之后都需要重新上电才可以…