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("executionStats")查看查询计划,关注executionTimeMillis和totalDocsExamined。如果扫描文档数远大于返回文档数,说明索引可能失效或缺失。
确保查询条件命中索引。避免在索引字段上使用函数或运算,例如YEAR(date)会导致索引失效,应使用范围查询。
当数据量超过单机存储或I/O瓶颈时,考虑分片。选择合适的分片键(Shard Key)至关重要,避免热点数据。
MongoDB使用WiredTiger存储引擎,默认分配50%的物理内存作为缓存。监控缓存命中率,确保热点数据在内存中。
常见慢查询场景
- 缺少索引:最基础的原因,检查查询字段是否有索引。
- 索引失效:使用了不等于($ne)、正则表达式(^)、类型转换等操作。
- 返回数据过大:查询返回了大量不需要的字段,应使用$project只返回必要字段。
- 深分页:使用skip()进行深分页效率极低,应使用基于范围的查询或游标分页。
高可用架构与集群部署
在企业级应用中,MongoDB通常以集群形式部署。了解其架构设计是高级职位的必考内容。
4.1 副本集 (Replica Set)
副本集是MongoDB高可用的基础。它包含多个数据节点,其中一个是Primary节点,负责写入操作;其他是Secondary节点,负责数据同步和读取备份。
- 自动故障转移:当Primary节点宕机时,副本集会自动选举新的Primary节点。
- 数据复制:通过Oplog(操作日志)实现异步复制,保证数据一致性。
- 读写分离:可以将读取请求路由到Secondary节点,减轻Primary压力。
4.2 分片集群 (Sharded Cluster)
当数据量达到TB级别或并发读写超过单机极限时,需要引入分片集群。分片集群由三部分组成:
- Shard:存储实际数据分片的服务器,每个Shard可以是副本集。
- Mongos:路由服务器,负责处理客户端请求,并将请求转发到对应的Shard。
- Config Server:配置服务器,存储集群的元数据和配置设置。
1. 高基数:分片键的值分布要均匀,避免数据倾斜。
2. 高频率:分片键应出现在查询条件中,以提高查询效率。
3. 避免热点:避免使用单调递增的字段(如自增ID)作为分片键,会导致写入集中在同一个分片。推荐使用哈希分片或随机前缀。