MongoDB系列之一文总结索引

news2024/12/26 0:49:46

概述

分类

索引的分类:

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

索引介绍

单键索引和复合索引

创建单键索引: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.coloradmin.cn/o/1406754.html

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

相关文章

QT 实现自动生成小学两位数加减法算式

小学生加减法训练 QT实现–自动生成两位数加减法算式,并输出txt文件 可以copy到word文件,设置适当字体大小和行间距,带回家给娃做做题 void MainWindow::test(int answerMax, int count) {// 创建一个随机数生成器QRandomGenerator *gener…

宝塔面板SRS音视频TRC服务器启动失败

首先,查找原因 1.先看srs服务在哪 find / -type f -name srs 2>/dev/null运行结果: /var/lib/docker/overlay2/5347867cc0ffed43f1ae24eba609637bfa3cc7cf5f8c660976d2286fa6a88d2b/diff/usr/local/srs/objs/srs /var/lib/docker/overlay2/5347867…

展厅设计更好的方法

一、与公司形象契合 在展厅规划时必定要留意公司的LOGO、主色调,以及企业文明。在展现时使用丰满的展厅规划传达出企业的理念。而在功用设置上,应当考虑内涵功用,从展厅作业人员的视点动身,为展厅作业人员提供杰出的环境&#xff…

L1-093 猜帽子游戏(Java)

宝宝们在一起玩一个猜帽子游戏。每人头上被扣了一顶帽子,有的是黑色的,有的是黄色的。每个人可以看到别人头上的帽子,但是看不到自己的。游戏开始后,每个人可以猜自己头上的帽子是什么颜色,或者可以弃权不猜。如果没有…

菜鸡后端的前端学习记录

前言 记录一下看视频学习前端的的一些笔记,以前对Html、Js、CSS有一定的基础(都认得,没用过),现在不想从头再来了,学学Vue框架,不定时更新,指不定什么时候就鸽了。。。。 Vue2 01…

elementui 表单 resetFields 方法不生效问题解决

问题 调用 elementui 官方提供的表单重置方法 resetFields 方法重置表单不生效,相信很多小伙伴都遇到过这个问题。 解决方法 检查代码看每个表单项的 prop 与 v-model 绑定的属性值命名是否相同,不相同的话就会导致 resetFields 方法不生效的问题&am…

「萌龙送宝」玉树芝兰定制红包封面免费发放

第二波红包封面,来了。 昨天晚上,我在公众号文章里免费发了 6000 份微信红包定制封面。根据 2022 年的经验,我原本以为这些红包怎么也得发个 12 小时,甚至是一天。但事实教育了我 —— 只用了半个小时,就发光了。 很多…

rabbitmq基础-java-1、快速入门

1、AMQP AMQP,即Advanced Message Queuing Protocol(高级消息队列协议),一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客…

Pygame之纯Python实现你好2024效果

Pygame之纯Python实现你好2024效果 前言: 对于某些指JavaScript与前端实现为Python实现你好2024效果的营销号实在看不下去了。无底线营销,还要私信拿源码,hhh 于是就有了以下代码: 运行前安装pygame pip install pygame运行效果…

apkpure下载Google Play中APP的APK安装包

比如Google Play上有个应用叫iSmart DV,想下载APK,怎么做呢 打开apkpure(https://apkpure.net/),输入对应的app名称即可下载

Integer.valueOf方法详解

Integer.valueOf 是 Java 中 Integer 类的一个静态方法,它用于将给定的字符串或基本数据类型转换成一个 Integer 对象。 使用场景 从字符串转换:将字符串形式的数字转换为 Integer 对象。 Integer num Integer.valueOf("123");从基本数据类…

springboot druid数据库配置密码加密

1.使用的druid版本 <!-- 阿里数据库连接池 --> <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.21</version> </dependency> 2.配置文件 # Spring配置 …

酷开科技 | 酷开系统全能基因 融合架构更多精彩

智能电视和智能电视操作系统早已不是新鲜事物&#xff0c;随着人们对智能电视的使用需求越来越多&#xff0c;一些消费者开始了探索电视的更多可能性&#xff0c;酷开科技通过对消费者群体的调研将酷开系统进行了创造性的升级&#xff0c;更强大的功能&#xff0c;让我们深切的…

openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具)

文章目录 openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具)概述效果笔记编程环境界面控件的设置增加文件拖拽的类RSA证书和key是否匹配的实现在程序中加入环境变量备注备注END openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具) 概述 在学习openssl官方的…

亚马逊、eBay、TikTok等平台的综合运营实用工具分享!

亚马逊、eBay等电商平台为卖家提供了广阔的销售机会&#xff0c;但同时也带来了运营管理的挑战。为了提高运营效率和销售业绩&#xff0c;卖家需要借助一些实用工具。本文将介绍一些在亚马逊、eBay等平台上综合运营中非常有用的工具&#xff0c;帮助卖家更高效地管理店铺&#…

【大数据】YARN调度器及调度策略

YARN调度器 YARN负责作业资源调度&#xff0c;在集群中找到满足业务的资源&#xff0c;帮助作业启动任务&#xff0c;管理作业的生命周期。 ​ YARN技术架构 ​ 目前&#xff0c;Hadoop作业调度器主要有三种&#xff1a;先进先出调度器&#xff08;First In First Out&…

Java安装环境JDK+Maven+Idea插件+nvm等

Java安装环境JDKMavenIdea插件nvm等 背景&#xff1a;新机安装开发环境发现需要找很多文章&#xff0c;&#xff0c;&#xff0c;&#xff0c;这里一篇文章安装所有环境 文章目录 Java安装环境JDKMavenIdea插件nvm等一、安装JDK①&#xff1a;下载②&#xff1a;安装③&#xf…

华媒舍:15种媒体发稿推广的创意理念与案例分析

媒体发稿已经成为推广知名品牌、产品与服务关键方式之一。怎样通过媒体发稿提升曝光度和吸引住受众却是一个挑战。下面我们就详细介绍15种创意理念和案例分析&#xff0c;帮助你更好地进行新闻媒体发稿推广。 1.造就日常生活小故事通过展示真实用户故事和感受&#xff0c;读者对…

Mysql数据库DQL查询语言之表连接(联合查询)

表连接 关系字段&#xff1a;两表中有关联关系的字段 \关系字段&#xff1a;两表之间存在关系的字段 什么是表连接&#xff1f; 当我们的查询结果需要从多张表中获取时&#xff0c;此时应该让表之间建立连接&#xff0c;同时获取数据 内连接 特点&#xff1a;同时对连接双方做…

configure: error: openSSL library not found.解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…