说一说mongodb组合索引的匹配规则
一、背景
有一张1000多万条记录的大表,需要做归档至历史表,出现了大量慢查询。
查询条件是
"classroomId": {$in: ["xxx", "xxx", ..... "xxx","xxx", "xxx" ] }
耗时近5秒,且是全表扫描

为什么没有使用到任何索引呢?
请看该集合创建的索引有哪些:

建立了两个组合索引userId_1_classroomId_1_isDelete_1和userId_1_classroomId_1,
但是二者的重复度极高。(可以删掉userId_1_classroomId_1_isDelete_1,再新建一个单索引classroomId_1)
二、组合索引
1、最左匹配原则
MongoDB 中组合索引遵循最左匹配原则,即在检索数据时从复合索引的最左边开始匹配。
举例来说,上文的组合索引userId_1_classroomId_1,对于查询条件 {“userId”: “xxx”, “classroomId”: “xxx”} 可以匹配该组合索引,因为查询条件包含了索引的最左前缀;而对于查询条件 {“classroomId”:“xxx”} 则无法匹配该组合索引。
但是对查询条件 {“userId”: “xxx”} 则可以匹配该组合索引。
所以,我们需要再新建一个单索引classroomId_1。
2、ESR规则
ESR(Equality, Sort, Range)规则是创建高效组合索引的一个重要原则
- Equality(相等):将需要精确匹配的字段放在索引的前面。这些字段用于过滤数据,减少需要扫描的文档数量。例如查询 db.xxx.find({“classroomId”: “GM03DI890”}) 中,classroomId 字段是精确匹配,应放在索引的前面。
- Sort(排序):排序操作应放在精确匹配字段之后。因为精确匹配可以减少需要排序的文档数量,且这样可以让 MongoDB 进行非阻塞排序。例如查询 db.xxx.find({“classroomId”: “GM03DI890”}).sort({createdOn: 1}) 中,createdOn 字段用于排序,应放在 classroomId 字段之后。
也就是说,组合索引的顺序应该是classroomId_1_createdOn_1 - Range(范围):范围查询字段应放在索引的最后面。范围查询会扫描一定范围内的数据,将其放在最后可以提高查询效率。例如查询 db.xxx.find({price: {$gte: 15000}}) 中,price 字段是范围查询,应放在索引的最后。
三、OR查询
如果是OR查询呢?
还是举如下例:
{"$or": [{"auth": 1},{"totalIds": {"$in": [1002482]}}]
}
应该分别对 auth 和 totalIds 字段创建单独的索引,而不是创建一个组合索引。
db.xxx.createIndex({"auth":1}, {"name":"auth_1","background":true})
db.xxx.createIndex({"totalIds":1}, {"name":"totalIds_1","background":true})
这是因为 MongoDB 在使用 or 查询时,如果每个子句都有自己的索引,那么 MongoDB 可以分别使用这些索引来执行查询,然后合并结果。这通常比创建一个包含所有字段的复合索引更有效。
1、区分度问题
区分度低的字段-- auth 字段的值只有两个(0 和 1),区分度很低。通常情况下,区分度低的字段单独建立索引的收益较小,因为索引的目的是快速定位数据,而区分度低的字段在索引中并不能有效减少需要扫描的数据量。
但我们还得考虑另外一个因素。
2、查询频率
如果 auth 字段在查询中非常频繁地被使用,即使区分度低,建立索引也可能带来一些性能提升。例如,如果大部分查询都包含 auth 字段,那么建立索引可以减少全表扫描的次数。
对于 or 查询,MongoDB 会分别使用每个子查询的索引,然后合并结果。
因此,为 auth 和 totalIds 分别建立单独的索引是合理的。这样可以确保每个子查询都能高效地使用索引。
四、执行计划
使用 explain 分析查询计划:
可以通过 explain 方法来分析查询计划,查看是否使用了索引以及索引的使用情况。
{"planSummary":"IXSCAN { totalIds: 1 }, IXSCAN { auth: 1 }"}
db.xxx.find({"$or":[{"auth":1},{"totalIds":{"$in":[636622]}}]}).explain("executionStats")

从执行计划可以看到,现在的OR查询能够使用到这两个单独索引。
五、总结
本文在OR查询中使用了分别创建两个单独索引来提高查询效率。
这里有一个问题,auth字段的区分度低,而totalIds字段的区分度高。
在索引及文档扫描的时候,整个查询的效率是取决于auth字段,尽管totalIds查询速度快。

上述OR查询语句,索引扫描行数以及文档扫描行数均为18000多。

从中也可以看出,区分度高和低,影响的检索效率高低。
改进:
- 从业务角度,考虑将auth查询与非auth查询分开来查询,这样就不会有OR查询场景
- 从数据库的角度,可以考虑分两张表,当要查询auth=0还是1的时候,从小表查询;如果没有auth查询,就可以使用totalIds字段,由于其区分度高,可以大大提高检索效率。
相关文章:
说一说mongodb组合索引的匹配规则
一、背景 有一张1000多万条记录的大表,需要做归档至历史表,出现了大量慢查询。 查询条件是 "classroomId": {$in: ["xxx", "xxx", ..... "xxx","xxx", "xxx" ] }耗时近5秒,且…...
Maven核心插件之maven-resources-plugin
前言 Maven 插件是 Maven 构建系统的重要组成部分,它们为 Maven 提供了丰富的功能和扩展能力,使得 Maven 不仅是一个构建工具,更是一个强大的项目管理平台。在 Maven 项目中,插件的使用通常通过配置 pom.xml 文件来完成。每个插件…...
C++ 鼠标轨迹算法 - 防止游戏检测
一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言,原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势: 模拟…...
网络学习记录6
查找下一跳和流量如何通过,是网络路由的基本概念。下面我会尽量用通俗易懂的方式来解释这个过程。 查找下一跳 数据包的目的地:当一个数据包在网络中传输时,它的目标是一个特定的IP地址。 路由表的作用:路由器有一个叫做路由表的东…...
【数学】概率论与数理统计(四)
文章目录 [toc] 分布函数分布函数性质离散型随机变量的分布函数连续型随机变量的分布函数示例1问题解答 正态随机变量示例问题解答 示例2问题(1)(2) 解答(1)(2) 随机变量函数的分布离…...
小结:华为交换机常用的操作指令
以下是华为交换机常用的操作指令总结,按功能分类说明: 1. 系统管理 进入系统视图system-view返回用户视图quit保存配置save查看当前配置display current-configuration重启设备reboot2. 用户管理 配置用户密码local-user <username> password ir…...
轻松学51单片机--基于普中科技开发板练习蓝桥杯及机器人大赛等(8-DS1302实时时钟)
1、DS1302 DS1302是一款实时时钟芯片,可以用于实时计时和日期显示等应用。它具有低功耗、精度高、芯片体积小等特点,非常适合嵌入式系统和小型电子设备中使用。 DS1302具有多个功能和特性,包括: 时钟功能:可以显示年…...
《Java核心技术II》并行流
并行流 从集合中获取并行流:Stream paralleWords words.parallelStream(); parallel方法将任意顺序流转换为并行流:Stream paralleWords Stream.of(wordArray).parallel(); 以下是不好的示范,假设对字符串的所有短单词计数: …...
Vue 3前端与Python(Django)后端接口简单示例
项目 后端(Django)前端(Vue 3) 后端(Django) 创建Django项目和应用: 确保你已经安装了Django。如果没有安装,可以使用以下命令安装: pip install django创建一个新的Dja…...
《拉依达的嵌入式\驱动面试宝典》—操作系统篇(二)
《拉依达的嵌入式\驱动面试宝典》—操作系统篇(二) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《拉…...
STM32和国民技术(N32)单片机串口中断接收数据及数据解析
一、串口配置 根据单片机不同,串口IO口配置也不同,像STM32单片机,RX脚可以配置为复用输出,也可以配置为浮空输入模式。但是国民技术单片机(N32)的RX是不能配置为复用输出模式的,这样是收不到数…...
【人工智能】大语言模型的微调:让模型更贴近你的业务需求
大语言模型的微调:让模型更贴近你的业务需求 随着大语言模型(LLM, Large Language Model)如 GPT-4、BERT 和 T5 等的广泛应用,模型的微调(Fine-tuning)技术成为实现领域专属任务的重要手段。通过微调&…...
大语言模型的稀疏性:提升效率与性能的新方向
大语言模型的稀疏性:提升效率与性能的新方向 大语言模型(LLM, Large Language Model)随着参数规模的不断扩大,其性能得到了显著提升,但也带来了巨大的计算和存储开销。稀疏性(Sparsity)作为一种…...
Linux Bridge与Open vSwitch的工作原理及协作
在虚拟化和云计算环境中,Linux Bridge和Open vSwitch(OVS)都是用于构建虚拟网络的关键组件。它们提供了二层交换功能,并且能够将虚拟机或容器连接到物理网络中。然而,两者在实现细节和技术特性上有所不同,下…...
async++源码阅读——task模块
1、task_base.h 本人将自己的理解以注释的形式添加的代码中,方便需要的时候重新复习。该文件中用到的一些技术: 该文件中的类并没有使用virtual,而是自定义了需函数表,但是并没有放到每个对象的开始位置,而是通过指针…...
项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(五)
文章目录 一、学生管理模块功能实现1、添加学生功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、学生管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码…...
EF Core一对一和多对多
目录 EF Core一对一 关系属性 关系配置 使用 EF Core多对多 关系属性 关系配置 使用 EF Core一对一 关系属性 必须显式的在其中一个实体类中声明一个外键属性,可以在Order建立Delivery,也可以在Delivery建立OrderId class Order {public long…...
记一次sealos部署k8s集群之delete了第一台master如何恢复
记一次sealos部署k8s集群之delete了第一台master如何恢复 一、背景描述 使用sealos部署了一套K8S集群 master信息:172.27.100.1、172.27.100.2、172.27.100.3 node信息:172.27.100.4、172.27.100.5 sealos安装在172.27.100.1节点,根目录下/root/.sealos/文件还在! [root…...
vue3+vite+ts集成第三方js
npm run dev可以正常运行和测试。但是npm run build会报错。 要实现引入静态js,避免使用全局变量报错。 1. HTML 引入第三方 JS 在你的 HTML 文件中,通过 <script> 标签引入一个本地第三方 JS 文件,例如: <script sr…...
android framework.jar 在应用中使用
在开发APP中,有时会使用系统提供的framework.jar 来替代 android.jar, 在gradle中配置如下: 放置framework.jar 依赖配置 3 优先级配置 gradle.projectsEvaluated {tasks.withType(JavaCompile) {Set<File> fileSet options.bootstrapClasspat…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
