跳到主要内容

MongoDB 与 MySQL 的区别

最高频的题目,几乎是 MongoDB 面试的必问开场。下面按维度逐条对比,最后给选型决策。

总览​

维度MySQL (InnoDB)MongoDB (WiredTiger)
数据模型关系型,二维表,行列固定文档型,BSON,字段可不同
Schema强制,变更要 DDL不强制(可选 JSON Schema 校验)
查询语言SQL(标准、通用)MQL + 聚合管道(私有)
关联JOIN,优化器自动选策略$lookup,能力弱、性能差
事务原生强项,默认 RR4.0+ 支持,设计上建议少用
索引结构B+ 树,主键聚簇B+ 树,非聚簇
锁粒度行锁(悲观阻塞)文档锁(乐观重试)
水平扩展需要中间件分库分表内置分片
高可用主从 + 哨兵 / MGR副本集(类 Raft,内置)
默认持久化每次提交 fsync内存写入即返回(可配)
压缩默认关闭默认 Snappy
嵌套 / 数组要 JSON 列或拆表原生支持,可直接建索引
生态成熟度极高,几乎所有工具都支持较好但不如 MySQL

逐维度展开​

1. 数据模型与 schema​

MySQL 的强 schema 是约束也是保障:类型错了插不进去、字段不存在会报错,数据质量有数据库层兜底。代价是变更成本 —— 加字段要 ALTER TABLE,大表上这是有风险的运维操作。

MongoDB 的灵活 schema 适合两类场景:

  • 字段频繁演进 —— 快速迭代的产品,今天加个字段明天改个结构
  • 字段本身就不统一 —— 商品属性因品类而异、第三方 API 返回结构不定、埋点事件各有各的 payload

关系库处理第二类场景只有三个不好的选择:大宽表(大量 NULL)、EAV 表(查询极其痛苦)、JSON 列(索引和查询能力有限)。

:::warning 「无 schema」是陷阱式表述 MongoDB 不是不需要设计 schema,而是把 schema 的维护责任从数据库转移到了应用层。实际后果:

  • 同一个集合里可能同时存在 userName / username / user_name 三种拼写
  • 某个字段有时是字符串有时是数字,查询条件写不对
  • 老数据缺少新加的字段,代码里到处是空值判断

所以成熟团队都会加 schema validation($jsonSchema)把约束加回来,并在应用层用类型定义(TypeScript interface / Go struct)统一。面试主动指出这一点,比单纯夸「灵活」显得更有经验。 :::

2. 关联查询​

这是最实际的差距。 MySQL 的 JOIN 有几十年的优化器积累(选驱动表、选择 Nested-Loop / Hash Join、下推谓词)。

MongoDB 的 $lookup 本质是嵌套循环,且:

  • 结果是数组,通常要跟 $unwind
  • 只有 LEFT OUTER JOIN 语义
  • 被关联集合的字段必须有索引,否则灾难
  • 分片集合支持有限、不能跨库

所以两者的建模思路根本不同:MySQL 靠拆表 + JOIN,MongoDB 靠嵌入 + 冗余。被问「MongoDB 怎么做多表关联」,标准答案是**「尽量不做 —— 通过嵌入或冗余在建模阶段消除关联需求」**,而不是介绍 $lookup 的用法。

3. 事务​

MySQL 的事务是基础能力:ACID 完备、MVCC 成熟、隔离级别可选、性能经过长期优化。

MongoDB 4.0+ 的多文档事务是真 ACID,但有 60 秒生命周期限制、长事务撑内存、分片下走 2PC 开销大,且官方建议优先靠建模规避。

核心差异在设计取向(这是得分点):

  • MySQL:规范化拆表 → 跨表一致性只能靠事务 → 事务是必需品
  • MongoDB:一个业务对象一个文档 → 单文档操作天然原子 → 事务是逃生舱

所以「MongoDB 里大量用事务」本身是一个建模警告信号。

4. 索引实现的差异​

两者都是 B+ 树,但组织方式不同:

InnoDB 聚簇索引 —— 数据存在主键索引的叶子节点里。

  • 主键查询:一次树查找直接拿到数据 ✅
  • 二级索引查询:先查二级索引拿主键,再回表 ⚠️
  • 推论:主键越大,所有二级索引都变大(叶子存主键值);主键随机会导致页分裂

WiredTiger 非聚簇 —— 所有索引叶子存 RecordId,数据单独存。

  • 连主键查询都要「回表」一次 ⚠️
  • 好处:没有「主键大小影响全部索引」的问题;没有随机主键导致的页分裂悬崖
  • 5.3+ 的 clustered collection 可以按 _id 聚簇,补上这个短板

MongoDB 索引的独有能力:数组字段(多键索引)、嵌套字段直接建索引("a.b.c")、TTL 自动过期、通配符索引。这些在 MySQL 里要么做不到要么很别扭。

5. 水平扩展​

MongoDB 的最硬优势。 分片是官方内置能力:加分片 → balancer 自动迁移 chunk → 应用无感。

MySQL 的分库分表需要 ShardingSphere / Vitess 等中间件或自研,且要自己处理全局 ID、跨库 JOIN、分布式事务、跨库分页。扩容通常意味着双写迁移和停机窗口。

但要公允地说两点:

  1. MongoDB 分片的分片键选择同样是不可逆的决策,选错了(基数不足、单调递增、不在高频查询条件里)照样是灾难,和 MySQL 选错分片键的后果一样严重
  2. MySQL 生态现在有 TiDB / OceanBase / PolarDB-X 这类分布式数据库,兼容 MySQL 协议且存储层自动分片,把这个差距大幅缩小了

6. 高可用​

MySQLMongoDB
组件主从 + 独立的哨兵进程 / MGR副本集内置,无需额外组件
选主哨兵选 leader 再挑新主类 Raft,节点间直接选举
防脑裂需手动配 min-replicas-to-write多数派天然保证,少数派的主自动降级
故障转移时间取决于配置,通常 10~30 秒约 10~12 秒
写确认级别innodb_flush_log_at_trx_commit + 半同步writeConcern(更细粒度,可按请求设)

MongoDB 在这一层设计更干净 —— 副本集是数据库自身的一部分,不是外挂方案,且 writeConcern 可以按单次操作指定(「这笔是订单,用 majority;这条是日志,用 w:1」),MySQL 只能全局配置。

7. 性能​

「MongoDB 比 MySQL 快」是个要拆解的说法:

  • 写入 —— 默认配置下 MongoDB 快,但很大程度上是因为默认持久化级别更弱(w:1, j:false 不等刷盘 vs InnoDB 每次提交 fsync)。调成同等可靠性(w:majority, j:true)后差距大幅缩小
  • 单文档读 —— 嵌入模型一次读取拿到完整对象,比多表 JOIN 快。但这是建模的胜利而非引擎的胜利
  • 复杂查询 / 聚合分析 —— MySQL 的优化器更成熟,复杂 SQL 通常更快且更好写
  • 高并发点查 —— 两者都能靠索引和内存做到很好,差异不大

:::tip 这个「默认持久化级别」的点很能加分 面试里说「MongoDB 写入快」很常见,但能主动补一句「不过这部分优势来自默认 writeConcern 更弱,调到同等可靠性后差距会小很多」,立刻显示出你理解的是机制而不是 benchmark 结论。 :::

🔥 选型决策​

选 MySQL​

  • 强事务 + 复杂关联 —— 支付、账务、ERP、库存
  • schema 稳定 —— 业务模型清晰且不常变
  • 重度分析 / BI —— SQL 的表达力和生态工具不可替代
  • 团队和生态 —— 运维经验、监控、备份、人才储备都更成熟
  • 默认选择 —— 没有明确理由选别的时,选 MySQL 是更稳妥的工程决策

选 MongoDB​

  • schema 易变或天然异构 —— 商品属性、埋点事件、CMS 内容、第三方数据
  • 以文档为单位读写 —— 一个业务对象一次性存取,没有复杂关联需求
  • 数据量预期持续高速增长 —— 需要内置的水平扩展
  • 时序 / 日志 / 物联网 —— 配合时序集合和分桶模式
  • 快速原型 —— 不想在需求未定型时反复改表结构
  • 地理空间查询 —— 2dsphere 比 MySQL 的空间扩展更好用

混合使用(现实中最常见)​

大中型系统基本都是组合:

MySQL —— 交易核心(订单、支付、账户),需要强一致
MongoDB —— 商品详情、内容、日志、埋点、配置
Redis —— 缓存、会话、排行榜、分布式锁
ES —— 全文搜索、复杂筛选、聚合分析

选型不是二选一,而是「哪部分数据交给哪个存储」。 被问「你会选 MySQL 还是 MongoDB」时,先问清业务场景再给结论,并说明分界线在哪 —— 这比直接站队任何一边都更好。

常见追问​

「MongoDB 是 CAP 里的哪个?」 默认偏 CP —— 网络分区时少数派不可写(保一致性)。但通过 readPreference: secondaryPreferred + w: 1 可以偏向 AP。所以准确答案是**「可调」**,CAP 的取舍点暴露给了应用。

「MongoDB 的锁比 MySQL 粒度更细吗?」 现在是同级的(文档 vs 行)。但历史上 MongoDB 很差 —— 2.2 之前是实例级锁,2.2~3.0 是库级锁,3.0 的 WiredTiger 才做到文档级。所以早年「MongoDB 并发差」的印象是真实的,只是已经过时了。知道这段历史能很好地回答这题。

「为什么有些公司从 MongoDB 迁回 MySQL?」 典型原因:当初选 MongoDB 只是为了「不想设计表结构」,但业务逐渐需要强一致和复杂关联;或者建模不当(大量 $lookup、无界数组),性能和维护成本双双恶化。教训是:选 MongoDB 要因为文档模型适合业务,而不是因为想逃避建模。

「MySQL 的 JSON 列能替代 MongoDB 吗?」 部分可以。MySQL 5.7+ 的 JSON 类型支持路径查询和虚拟列索引,适合「大部分字段固定 + 少量扩展属性」的场景。但差距在:JSON 列的索引要手动建虚拟列、没有数组元素索引、没有聚合管道、更新子字段的性能差、没有内置分片。如果异构数据只占一小部分,用 MySQL JSON 列是更省事的选择;如果整个数据模型都是文档形态,用 MongoDB。