首页 > 数据库 >【后端面试题】【中间件】【NoSQL】MongoDB查询优化3(拆分、嵌入文档,操作系统)

【后端面试题】【中间件】【NoSQL】MongoDB查询优化3(拆分、嵌入文档,操作系统)

时间:2024-07-07 19:29:26浏览次数:14  
标签:面试题 嵌入 NoSQL MongoDB 中间件 查询 文档 拆分 优化

拆分大文档

很常见的一种优化手段,在一些特定的业务场景中,会有一些很大的文档,这些文档有很多字段,而且有一些特定的字段还特别的大。可以考虑拆分这些文档

大文档对MongoDB的性能影响还是很大的,就我个人经验而言,认为可以考虑从两个角度出发拆分大文档:

  1. 按照字段的访问频率拆分: 访问频繁的放一个文档,访问不频繁的拆出去作为另一个文档
  2. 按照字段的大小来划分: 小字段放一个文档,大字段拆除去作为另外一个文档

之前拆分过一个文档,非常庞大。而且在业务中,有一些庞大的字段根本用不上,在这种情况下,一次拆除了三个文档。

  • 访问频繁的小字段放在一起,作为一个文档
  • 访问不频繁的大字段拆出去作为一个文档。可以进一步优化为特定的巨大的字段可以直接作为一个文档
  • 剩余的合并在一起作为一个文档

这样做的优点很明显,比较多的业务查询其实只需要第一种文档,极少数会需要第二种文档;但是缺点也很明显,如果调用者需要整个文档,也就意味着需要查询三次,再合并组成一个业务上完整的文档。

也可以升华一下:这种拆分终究是下策,最好还是在一开始使用MongoDB的时候就约束住文档的大小。
不过还有一个和这种策略完全相反的优化手段:嵌入文档

嵌入文档

如果A文档和B文档有关联关系,那么就在A文档里面嵌入B文档,做成一个大文档。
相当于原本A文档和B文档都是单独存储的,可能A文档里面有一个B文档的ID字段,又或者B文档里有A文档的ID字段,可以考虑合并这两个文档

在这里插入图片描述
可以这么介绍你的方案:

早期有一个过度设计的场景,就是有两个文档A和B,其中A里面有一个B的文档ID,建立了一对一的映射关系。但是实际上,业务查询的时候,基本上是分两次查询的,先把A查询出来,再根据A里面的文档ID也把B查出来
后来这个地方慢慢成为了性能瓶颈,我就尝试优化了这个地方。我的想法是既然A和B在业务上联系那么紧密,我可以直接把他们整合成一个文档。整合之后,一次查询就能拿到所有需要的数据了,直接节约了一个MongoDB查询,提高了业务的响应时间,而且MongoDB的压力也变小了。

如果面试官问怎么直接整合成一个文档呢?

采用的是懒惰的、渐进式的整合方案。如果我先查询A文档之后发现A文档还没有嵌入B文档,那么就查询B文档,嵌入进A文档之后,直接更新A文档。在更新A文档的时候,要采用乐观锁策略,也就是在更新的条件里,加上A文档不包含B文档这个条件。

这个业务有一个好处是,没有直接更新B文档的场景,都是通过A来操作B文档,所以不需要考虑其他的并发问题

在这里插入图片描述
这种懒惰更新策略里的最后一步更新动作,实际上就是一个乐观锁。所以也可以尝试把话题引导到乐观锁上

不过,嵌入整个文档是很罕见的优化手段。更加常见的是嵌入部分字段,也叫做冗余字段。这种优化手段在关系型数据库里也很常见,比如A经常使用B的某几个字段,那么就可以在A里面冗余一份。但是这种冗余的方案会有比较严重的数据一致性问题,只有在你能够容忍这种数据不一致的时候,才可以应用这个方案。
在现实中最常见的场景就是在别的模块的文档里冗余用户的昵称、头像,这样可以避免再次去用户文档里查询昵称或头像。毕竟这两个在很多时候都不是什么关键字段。

操作系统优化

前面基本都是查询本身的优化,也可以准备一些操作系统优化的点。

内存优化

在MongoDB里,索引对性能的影响很大,所以应该尽可能保证有足够的物理内存来放所有的索引。

swap

同样需要避免触发交换,可以调小vm.swappiness 这个参数

标签:面试题,嵌入,NoSQL,MongoDB,中间件,查询,文档,拆分,优化
From: https://blog.csdn.net/LightOfNight/article/details/140233224

相关文章

  • 【后端面试题】【中间件】【NoSQL】MongoDB提高可用性的方案(主从结构、仲裁节点、分片
    主从结构MongoDB的高可用和别的中间件的高可用方案基本类似。比如在MySQL里,接触了分库分表和主从同步;在Redis里,Redis也有主从结构;在Kafka里,分区也是有主从结构的。所以先介绍启用了主从同步我们的系统有一个关键组件-MongoDB,但是在最开始的时候,MongoDB没有启用主从,是......
  • 【大模型LLM面试合集】大语言模型基础_NLP面试题
    NLP面试题1.BERT1.1基础知识BERT(BidirectionalEncoderRepresentationsfromTransformers)是谷歌提出,作为一个Word2Vec的替代者,其在NLP领域的11个方向大幅刷新了精度,可以说是近年来自残差网络最优突破性的一项技术了。论文的主要特点以下几点:使用了双向Transformer作......
  • Apache Drill 2万字面试题及参考答案
    目录什么是ApacheDrill?ApacheDrill的主要特点是什么?ApacheDrill如何实现对复杂数据的查询?描述ApacheDrill的数据存储模型。为什么ApacheDrill被称为自服务的SQL查询引擎?ApacheDrill支持哪些类型的数据源?解释ApacheDrill中的“schemadiscovery”功能。如何在Apa......
  • Java面试之并发与网络通信常见面试题
    并发编程部分1.什么是进程和线程?进程:操作系统分配资源的最小单位,各个进程之间占据独立的寻址空间,运行也是独立运行,进程间通信需要一些机制。线程:程序执行的基本单位,一个进程可以开启多个线程,他们的很多空间(如堆空间)是公用的。线程执行开销小,但是不够安全。2.线程有几......
  • Android面试题自定义View之Window、ViewRootImpl和View的三大流程
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点View的三大流程指的是measure(测量)、layout(布局)、draw(绘制)。下面我们来分别看看这三大流程View的measure(测量)MeasureSpecMeasureSpec是View的一个内部静......
  • 代码随想录算法训练营第四天 | 24. 两两交换链表中的节点 、 19.删除链表的倒数第N个
    24.两两交换链表中的节点 题目:.-力扣(LeetCode)思路:这题关键是要每次进行两个结点的操作,并且每次都要保存其前结点,做题思路比较清晰,但是总是处理不好边界问题,总是越界。代码:/***Definitionforsingly-linkedlist.*structListNode{*intval;*List......
  • 代码随想录刷题day 4 | 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题
    24.两两交换链表中的节点迭代的版本:最重要的就是要知道循环变量怎么取,对于这道题,我们只需要存储需要交换的两个节点的前一个节点即可,只有当这个节点后面有两个节点时才进入循环,其实把握住这一点之后这题就非常容易了。递归的版本:这道题用递归做简直不要太简单,首先明白递归结束......
  • Linux常用面试题
    系统部分1、在linux系统中,获取命令帮助的方法有哪些?   man(查看手册页)    help(查看内部命令)   --help(查看外部命令)2、列举find命令的用法?(主要说明使用的选项及其含义)   find查找文件或目录      -name   根据目标的名称进程查找,允许使......
  • Linux系统管理面试题
    中级系统管理面试题训练内容:1)编译安装源代码的过程?      从官方网站下载源码包校验md5值   解压   tar命令解包      配置   进入解压目录配置,指定对应的模块、解包的路径   编译   源代码编译成二进制文件      安装 ......
  • Java面试题系列 - 第4天
    题目:深入理解Java泛型与类型擦除背景说明:Java泛型是JavaSE5引入的一种新特性,它允许在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。然而,Java泛型的实现背后有一个重要的概念——类型擦除,理解这一点对于深入掌握泛型编程至关重要。问题要求:解......