导读:本期聚焦于小伙伴创作的《MongoDB 28个高频面试题详解:索引、复制集、分片与性能优化全解析》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《MongoDB 28个高频面试题详解:索引、复制集、分片与性能优化全解析》有用,将其分享出去将是对创作者最好的鼓励。

28个MongoDB经典面试题详解

MongoDB作为非关系型数据库的代表,在招聘面试中出现的频率非常高。本文整理了28个高频面试题,覆盖基础概念、操作、索引、复制集、分片、性能优化等核心知识点,帮助大家系统梳理MongoDB相关知识。

一、基础概念类面试题

1. 什么是MongoDB?它和关系型数据库有什么区别?

MongoDB是一个基于分布式文件存储的开源数据库系统,由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。它属于NoSQL数据库,和传统关系型数据库的核心区别如下:

对比维度关系型数据库(如MySQL)MongoDB
数据模型二维表结构,行和列固定文档型结构,数据以BSON(类JSON)格式存储,结构灵活
Schema约束建表时需定义字段类型、长度等约束,修改结构成本高无固定Schema,同一个集合中的文档可以有不同的字段
事务支持早期仅支持单文档事务,现在支持分布式事务4.0版本后支持多文档ACID事务
扩展方式垂直扩展为主,水平扩展复杂度高原生支持水平扩展,通过分片机制实现

2. MongoDB中的核心概念有哪些?分别是什么作用?

MongoDB的核心概念和高频对应关系如下:

  • 数据库(Database):MongoDB中最高级别的存储单元,一个MongoDB实例可以包含多个数据库,不同数据库的数据物理隔离。

  • 集合(Collection):对应关系型数据库中的表,是文档的容器,集合中的文档不需要有统一的字段结构。

  • 文档(Document):MongoDB中最小的数据存储单元,对应关系型数据库中的行,以BSON格式存储,支持嵌套和数组类型。

  • 字段(Field):对应文档中的键值对,类似关系型数据库中的列。

  • _id:每个文档默认自带的主键字段,类型为ObjectId,保证文档的唯一性,也可以自定义该字段的值。

3. BSON和JSON有什么区别?

BSON是Binary JSON的缩写,是MongoDB存储数据的底层格式,和JSON的主要区别如下:

  • JSON是文本格式,BSON是二进制格式,解析速度更快,存储空间更小。

  • BSON支持更多数据类型,比如Date、Binary Data、ObjectId、Regular Expression等,JSON仅支持字符串、数字、布尔、数组、对象、null等基础类型。

  • BSON支持在编码时记录字符串的长度,遍历时不需要像JSON一样逐个字符解析,效率更高。

4. MongoDB适合哪些应用场景?不适合哪些场景?

适合的场景:

  • 数据结构灵活多变,Schema经常变化的业务,比如内容管理系统、用户行为日志存储。

  • 需要快速水平扩展的业务,比如高并发的社交应用、物联网设备数据存储。

  • 对读写性能要求高,且不需要复杂多表关联查询的场景。

不适合的场景:

  • 需要复杂事务支持、多表强关联查询的金融类核心业务,比如银行转账系统。

  • 数据一致性要求极高的场景,比如涉及资金结算的核心交易系统。

二、基础操作类面试题

5. 如何创建、查看、删除数据库和集合?

以下是MongoDB shell中的常用操作命令:

# 切换到指定数据库,如果数据库不存在,会在插入第一条数据时自动创建
use test_db

# 查看当前连接的数据库
db

# 查看所有数据库(只显示有数据的数据库)
show dbs

# 创建集合,不指定选项时直接使用db.createCollection("集合名")
db.createCollection("user")

# 查看当前数据库下的所有集合
show collections

# 删除当前数据库下的指定集合
db.user.drop()

# 删除当前数据库
db.dropDatabase()

6. 如何向集合中插入、查询、更新、删除文档?

基础CRUD操作示例如下:

# 插入单条文档,insertOne方法返回插入的文档_id
db.user.insertOne({name: "张三", age: 25, hobby: ["篮球", "阅读"]})

# 插入多条文档,insertMany方法接收文档数组
db.user.insertMany([
  {name: "李四", age: 28, hobby: ["足球"]},
  {name: "王五", age: 22, hobby: ["游戏", "跑步"]}
])

# 查询所有文档
db.user.find()

# 条件查询,查询age大于25的文档
db.user.find({age: {$gt: 25}})

# 查询指定字段,1表示返回,0表示不返回,_id默认返回,需要显式设置0才不返回
db.user.find({age: {$gt: 25}}, {name: 1, age: 1, _id: 0})

# 更新单条文档,将name为张三的文档age更新为26
db.user.updateOne({name: "张三"}, {$set: {age: 26}})

# 更新多条文档,将所有age小于25的文档增加标签"年轻用户"
db.user.updateMany({age: {$lt: 25}}, {$push: {tags: "年轻用户"}})

# 删除单条文档,删除name为王五的文档
db.user.deleteOne({name: "王五"})

# 删除多条文档,删除age大于30的所有文档
db.user.deleteMany({age: {$gt: 30}})

7. MongoDB中的比较操作符有哪些?分别是什么作用?

常用的比较操作符如下:

  • $eq:等于,比如{age: {$eq: 25}}等价于{age: 25}

  • $ne:不等于

  • $gt:大于

  • $gte:大于等于

  • $lt:小于

  • $lte:小于等于

  • $in:匹配数组中任意一个值,比如{age: {$in: [22, 25, 28]}}

  • $nin:不匹配数组中任意一个值

8. 如何对查询结果进行排序、分页?

排序使用sort()方法,参数中1表示升序,-1表示降序;分页使用skip()跳过指定数量的文档,limit()限制返回的文档数量:

# 按age升序排序,如果age相同按name降序排序
db.user.find().sort({age: 1, name: -1})

# 分页查询,每页10条,查询第2页数据(跳过前10条,返回接下来10条)
db.user.find().skip(10).limit(10)

三、索引相关面试题

9. 什么是MongoDB索引?为什么需要索引?

索引是MongoDB中特殊的数据结构,保存了集合中某个字段或字段集的值,以及这些值对应的文档在磁盘上的存储位置。作用和关系型数据库的索引类似:

  • 没有索引时,查询需要全集合扫描,数据量大时效率极低。

  • 创建索引后,查询可以直接通过索引快速定位到目标文档,大幅提升查询效率。

  • 但是索引会占用额外的存储空间,且会降低插入、更新、删除操作的性能,因为每次写操作都需要同步更新索引。

10. MongoDB支持哪些类型的索引?

常用的索引类型如下:

  • 单字段索引:对单个字段创建的索引,是最基础的索引类型。

  • 复合索引:对多个字段组合创建的索引,查询时如果遵循最左前缀原则,索引才会生效。

  • 多键索引:对数组类型的字段创建的索引,比如文档中的hobby是数组,对hobby创建索引就是多键索引。

  • 文本索引:支持对字符串内容做全文检索,一个集合只能创建一个文本索引,可以包含多个字段。

  • 地理空间索引:支持对地理坐标类型的字段做位置查询,比如查找附近的商家。

  • 哈希索引:对字段值做哈希计算后存储的索引,只支持等值查询,不支持范围查询。

11. 如何创建、查看、删除索引?

操作示例如下:

# 对user集合的age字段创建升序单字段索引
db.user.createIndex({age: 1})

# 创建复合索引,先按age升序,再按name降序
db.user.createIndex({age: 1, name: -1})

# 创建文本索引,对name和hobby字段做全文检索
db.user.createIndex({name: "text", hobby: "text"})

# 查看集合的所有索引
db.user.getIndexes()

# 删除指定索引,通过索引名删除,比如删除age_1索引
db.user.dropIndex("age_1")

# 删除集合的所有索引(除了_id字段的默认索引)
db.user.dropIndexes()

12. 什么是索引的最左前缀原则?

最左前缀原则针对复合索引生效:如果创建的复合索引是{a: 1, b: 1, c: 1},那么以下查询可以使用该索引:

  • 查询条件包含a字段

  • 查询条件包含a和b字段

  • 查询条件包含a、b、c三个字段

以下查询无法使用该复合索引:

  • 仅查询b字段

  • 仅查询c字段

  • 查询b和c字段

如果将查询条件的字段顺序调整为a、b、c(和索引定义的顺序无关,MongoDB会自动优化),只要包含最左边的字段就可以命中索引。

13. 如何分析查询是否使用了索引?

可以使用explain()方法分析查询的执行计划,查看索引使用情况:

# 分析查询的执行计划,executionStats模式会返回详细的执行统计信息
db.user.find({age: 25}).explain("executionStats")

执行结果中需要重点关注的字段:

  • winningPlan.inputStage.stage:如果是IXSCAN表示使用了索引扫描,如果是COLLSCAN表示全集合扫描。

  • executionStats.totalDocsExamined:扫描的文档数量,如果该值远小于集合总文档数,说明索引生效。

  • executionStats.totalKeysExamined:扫描的索引键数量,正常情况下应该和返回的文档数量接近。

四、复制集相关面试题

14. 什么是MongoDB复制集?有什么作用?

复制集是一组维护相同数据集的MongoDB实例,包含一个主节点(Primary)和多个从节点(Secondary),作用如下:

  • 数据冗余:从节点会异步复制主节点的数据,即使主节点故障,数据也不会丢失。

  • 高可用:主节点故障时,复制集会自动触发选举,从从节点中选出一个新的主节点,保证服务不中断。

  • 读写分离:可以将读请求分发到从节点,减轻主节点的压力,提升整体吞吐量。

15. 复制集的主从节点有什么区别?读写请求如何分配?

  • 主节点是唯一可以接收写请求的节点,所有写操作都会记录到主节点的oplog(操作日志)中。

  • 从节点会异步拉取主节点的oplog,并重放这些操作,从而保持和主节点的数据同步。

  • 默认情况下,读请求也可以发送到主节点,从节点默认不可读,需要手动设置slaveOk才可以从从节点读取数据。

  • 注意:从节点的数据同步存在延迟,读从节点可能会读到旧数据,需要根据业务场景选择是否开启读写分离。

16. 复制集的选举机制是什么?

当主节点不可用(比如宕机、网络断开)时,复制集会触发选举流程:

  • 所有从节点会检测主节点是否存活,如果主节点超过配置的选举超时时间没有响应,从节点就会发起选举。

  • 每个从节点会给自己投票,同时请求其他节点给自己投票,获得多数票(超过复制集总节点数的一半)的节点会当选新的主节点。

  • 为了防止脑裂(出现多个主节点),复制集的节点数建议设置为奇数,比如3节点、5节点。

17. 如何搭建一个3节点的MongoDB复制集?

步骤如下:

  1. 准备3台服务器(或同一台服务器的3个不同端口),分别创建数据存储目录和配置文件。

  2. 每个实例的配置文件需要指定replication.replSetName为相同的复制集名称,比如rs0

  3. 启动3个MongoDB实例,然后连接到任意一个实例,执行初始化复制集的命令:

# 初始化复制集,指定三个节点的地址和端口
rs.initiate({
  _id: "rs0",
  members: [
    {_id: 0, host: "127.0.0.1:27017"},
    {_id: 1, host: "127.0.0.1:27018"},
    {_id: 2, host: "127.0.0.1:27019"}
  ]
})

# 查看复制集状态
rs.status()

五、分片相关面试题

18. 什么是MongoDB分片?什么时候需要用到分片?

分片是将数据分散存储到多个机器上的机制,每个机器上的数据集合称为一个分片(Shard),所有分片的数据组合起来是整个数据集。需要用到分片的场景:

  • 单台机器的存储容量无法容纳全部数据,需要水平扩展存储。

  • 单台机器的读写吞吐量达到瓶颈,需要分散请求压力。

  • 数据量增长快,需要提前做好扩展规划,避免后续迁移成本过高。

19. 分片集群包含哪些组件?分别是什么作用?

MongoDB分片集群由三个核心组件组成:

  • 分片(Shard):实际存储数据的节点,每个分片可以是单个MongoDB实例,也可以是一个复制集,生产环境建议分片使用复制集保证高可用。

  • 配置服务器(Config Server):存储分片集群的元数据,包括分片和数据块的映射关系、集群的配置信息等,配置服务器也需要是复制集,防止单点故障。

  • 查询路由(Mongos):客户端连接的中间件,负责将客户端的请求路由到对应的分片,对客户端来说,分片集群就像是一个普通的MongoDB实例,不需要关心数据具体存在哪个分片。

20. 什么是片键(Shard Key)?选择片键有什么原则?

片键是分片集合中用于划分数据的字段,MongoDB会根据片键的值将数据分散到不同的分片。选择片键的原则:

  • 基数要高:片键的不同值要足够多,避免数据集中到少数几个分片,比如不要选择性别这种只有两个值的字段作为片键。

  • 写分布均匀:片键的值要随机分布,避免大量写操作集中到同一个分片,比如不要选择自增的ID作为片键,否则所有新写入的数据都会进入同一个分片。

  • 查询友好:片键要和业务查询的常用条件匹配,这样查询可以直接路由到对应的分片,不需要广播到所有分片。

  • 避免单调递增或递减:否则会导致数据热点,影响分片的负载均衡效果。

21. 分片和复制集的区别是什么?

两者的核心区别如下:

对比维度复制集分片
核心目标数据冗余、高可用水平扩展存储和吞吐量
数据存储所有节点存储全量数据每个分片只存储部分数据,所有分片数据组合为全量数据
写请求只有主节点可以处理写请求写请求可以根据片键分散到不同分片处理
扩展性扩展能力有限,主要提升可用性可以无限水平扩展,适合大数据量场景

六、性能优化类面试题

22. 如何定位MongoDB的性能问题?

常用的定位方法:

  • 开启慢查询日志,记录执行时间超过阈值的操作,分析慢查询的原因:

# 设置慢查询阈值为100毫秒,超过100ms的操作会被记录到日志中
db.setProfilingLevel(1, 100)

# 查看慢查询记录
db.system.profile.find().sort({ts: -1}).limit(10)
  • 使用explain()分析查询的执行计划,查看是否使用了合适的索引,是否存在全集合扫描。

  • 监控服务器的资源使用情况,包括CPU、内存、磁盘IO、网络带宽,判断是否是硬件资源瓶颈。

  • 查看复制集或分片的负载情况,判断是否是某个节点负载过高导致整体性能下降。

23. 有哪些常见的MongoDB性能优化手段?

可以从以下几个方面优化:

  • 索引优化:根据查询条件创建合适的索引,删除无用索引,避免索引过多影响写性能;遵循最左前缀原则设计复合索引。

  • 查询优化:只返回需要的字段,避免返回大量无用数据;合理使用分页,避免一次性查询过多数据;尽量让查询命中索引,减少全集合扫描。

  • 写入优化:批量写入比单条写入效率高,尽量使用insertManyupdateMany等批量操作;对于大量写入场景,可以暂时关闭不需要的索引,写入完成后再重建。

  • 硬件优化:使用SSD存储提升磁盘IO性能;保证足够的内存,MongoDB会尽可能将热数据缓存到内存中,内存不足会导致频繁的磁盘读写。

  • 架构优化:读多写少的场景可以开启读写分离,将读请求分发到从节点;数据量大的场景可以引入分片,分散存储和请求压力。

24. MongoDB的内存管理机制是什么?

MongoDB使用操作系统的虚拟内存机制,同时内置了类似操作系统的页缓存机制:

  • MongoDB会尽可能将常用的数据和索引加载到内存中,称为工作集(Working Set)。

  • 如果工作集大小小于可用内存,MongoDB的读写性能会非常高,因为大部分操作可以直接在内存中完成。

  • 如果工作集大小超过可用内存,MongoDB会触发页换出,将不常用的数据写到磁盘,此时性能会大幅下降。

  • 建议生产环境给MongoDB分配足够的内存,保证工作集可以完全放在内存中。

七、事务与一致性类面试题

25. MongoDB的事务支持有什么特点?

MongoDB 4.0版本开始支持多文档ACID事务,特点如下:

  • 事务可以保证多个文档的读写操作要么全部成功,要么全部失败,满足ACID特性。

  • 事务需要在复制集或分片集群环境下使用,单节点实例不支持事务。

  • 事务有执行时间限制,默认是60秒,超过时间会自动回滚,避免长时间占用资源。

  • 事务中的操作会加锁,并发的事务如果操作相同的数据可能会产生冲突,需要根据业务场景合理设计事务范围,避免大事务。

26. MongoDB的读写关注(Write Concern和Read Concern)是什么?

  • Write Concern(写关注):指定写操作的确认级别,比如:

    • {w: 1}:写操作只要主节点确认就返回成功,是默认级别。

    • {w: "majority"}:写操作需要大多数节点(超过半数)确认才返回成功,保证数据不会因主节点故障而丢失。

    • {j: true}:写操作需要写入日志才返回成功,进一步保证数据持久性。

  • Read Concern(读关注):指定读操作的数据一致性级别,比如:

    • "local":读取最新的数据,可能会读到未提交的事务数据,是默认级别。

    • "majority":只读取已经被大多数节点确认的数据,保证读到的数据是持久化的,不会回滚。

    • "snapshot":读取事务开始时的快照数据,保证可重复读。

八、其他高频面试题

27. 如何备份和恢复MongoDB的数据?

MongoDB提供了mongodumpmongorestore工具用于备份和恢复:

# 备份整个数据库,输出到指定目录
mongodump --host 127.0.0.1 --port 27017 --out /data/backup/mongo_backup_20240501

# 备份指定的数据库
mongodump --host 127.0.0.1 --port 27017 --db test_db --out /data/backup/test_db_backup

# 恢复整个备份数据到MongoDB
mongorestore --host 127.0.0.1 --port 27017 /data/backup/mongo_backup_20240501

# 恢复指定数据库的数据,--drop表示恢复前先删除目标数据库中的原有数据
mongorestore --host 127.0.0.1 --port 27017 --db test_db --drop /data/backup/test_db_backup/test_db

28. 生产环境部署MongoDB有哪些注意事项?

  • 复制集节点数建议为奇数,至少3节点,保证选举可以正常进行,避免脑裂。

  • 分片集群的分片建议使用复制集,配置服务器也必须使用复制集,保证元数据安全。

  • 关闭MongoDB的公开访问端口,只允许内网IP访问,避免数据泄露。

  • 定期备份数据,验证备份数据的可恢复性,防止数据丢失。

  • 开启慢查询日志,定期分析慢查询,优化索引和查询语句。

  • 监控MongoDB的各项指标,包括CPU、内存、磁盘、连接数、操作延迟等,设置合理的告警阈值。

  • 版本选择上,优先选择官方长期支持的稳定版本,避免使用最新但未经过大规模验证的版本。

MongoDB面试题 MongoDB索引 MongoDB复制集 MongoDB分片 MongoDB性能优化

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。