MongoDB概述与基础核心

在准备MongoDB面试时,首先需要对NoSQL数据库的基本概念有清晰的认识。MongoDB是一款基于分布式文件存储的NoSQL数据库,由C++语言编写,旨在为Web应用提供可扩展的高性能数据存储解决方案。它的特点是高性能、易部署、易使用,存储数据非常方便。

1.1 为什么选择MongoDB?

面试官常问:“MongoDB与MySQL相比有什么优势?”

  • 模式自由(Schema-free):不需要预先定义表结构,文档结构灵活,适合快速迭代的项目。
  • 面向集合存储:数据存储在集合中,类似于关系型数据库中的表,但更灵活。
  • 支持丰富的查询语言:支持JSON风格的查询,功能强大且直观。
  • 高效的二进制存储:支持BSON(Binary JSON)格式,存储和传输效率高。
  • 内置分片机制:原生支持水平扩展,轻松应对海量数据。

1.2 BSON与JSON的区别

MongoDB内部使用BSON(Binary Serialized Document)格式存储数据。与JSON相比,BSON支持更多的数据类型,如Date、Binary Data、ObjectId等,且解析速度更快。在面试中,理解BSON的结构有助于理解MongoDB的存储机制。

进阶实战:聚合管道与索引优化

这是面试中最具技术含量的部分,通常涉及复杂的查询优化和数据处理。

聚合管道工作原理

MongoDB的聚合框架(Aggregation Framework)用于处理数据记录并返回计算结果。管道由多个阶段(Stage)组成,数据在每个阶段被转换。常见的阶段包括:

  • $match:过滤数据,只输出符合条件的文档。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • skip:控制输出文档数量。
  • $project:重塑文档结构,如重命名字段、计算新字段。

面试示例:如何统计每个用户在过去一个月的订单总金额?

db.orders.aggregate([
  { gte: new Date("2024-04-01") } } },
  { $group: {
      _id: "$userId",
      totalAmount: { amount" },
      orderCount: { $sum: 1 }
  }},
  { $sort: { totalAmount: -1 } },
  { $limit: 10 }
])

索引类型与优化策略

索引是提升MongoDB查询性能的关键。常见的索引类型包括:

索引类型 描述 适用场景
单字段索引 基于单个字段创建的索引 简单查询条件
复合索引 基于多个字段创建的索引 多字段联合查询
多键索引 自动为数组字段创建索引 数组字段查询
地理空间索引 2dsphere或2d索引 地理位置查询
全文索引 Text Index 文本搜索
💡 最佳实践:遵循最左前缀原则。在复合索引中,查询条件必须包含索引的最左前缀字段才能命中索引。

MongoDB事务处理

自MongoDB 4.2起,生产环境支持多文档事务。这在需要保证数据一致性的场景下至关重要。

事务使用示例:

const session = client.startSession();
try {
  await session.withTransaction(async () => {
    await collectionA.insertOne({ ... }, { session });
    await collectionB.updateOne({ ... }, { ... }, { session });
  });
} finally {
  await session.endSession();
}

注意事项:事务会增加系统开销,避免在高频短事务中使用。同时,事务中不要包含长时间运行的操作。

性能优化与常见问题排查

面试官通常会考察候选人对数据库性能调优的实战经验。以下是几个关键的优化方向:

🔍
使用explain()分析查询

通过explain("executionStats")查看查询计划,关注executionTimeMillis和totalDocsExamined。如果扫描文档数远大于返回文档数,说明索引可能失效或缺失。

📊
避免全表扫描

确保查询条件命中索引。避免在索引字段上使用函数或运算,例如YEAR(date)会导致索引失效,应使用范围查询。

📦
合理分片与分库

当数据量超过单机存储或I/O瓶颈时,考虑分片。选择合适的分片键(Shard Key)至关重要,避免热点数据。

💾
内存管理(WiredTiger)

MongoDB使用WiredTiger存储引擎,默认分配50%的物理内存作为缓存。监控缓存命中率,确保热点数据在内存中。

常见慢查询场景

  • 缺少索引:最基础的原因,检查查询字段是否有索引。
  • 索引失效:使用了不等于($ne)、正则表达式(^)、类型转换等操作。
  • 返回数据过大:查询返回了大量不需要的字段,应使用$project只返回必要字段。
  • 深分页:使用skip()进行深分页效率极低,应使用基于范围的查询或游标分页。

高可用架构与集群部署

在企业级应用中,MongoDB通常以集群形式部署。了解其架构设计是高级职位的必考内容。

4.1 副本集 (Replica Set)

副本集是MongoDB高可用的基础。它包含多个数据节点,其中一个是Primary节点,负责写入操作;其他是Secondary节点,负责数据同步和读取备份。

  • 自动故障转移:当Primary节点宕机时,副本集会自动选举新的Primary节点。
  • 数据复制:通过Oplog(操作日志)实现异步复制,保证数据一致性。
  • 读写分离:可以将读取请求路由到Secondary节点,减轻Primary压力。

4.2 分片集群 (Sharded Cluster)

当数据量达到TB级别或并发读写超过单机极限时,需要引入分片集群。分片集群由三部分组成:

  1. Shard:存储实际数据分片的服务器,每个Shard可以是副本集。
  2. Mongos:路由服务器,负责处理客户端请求,并将请求转发到对应的Shard。
  3. Config Server:配置服务器,存储集群的元数据和配置设置。
⚡ 分片键选择原则:
1. 高基数:分片键的值分布要均匀,避免数据倾斜。
2. 高频率:分片键应出现在查询条件中,以提高查询效率。
3. 避免热点:避免使用单调递增的字段(如自增ID)作为分片键,会导致写入集中在同一个分片。推荐使用哈希分片或随机前缀。