摘要
TiDB(关系型分布式数据库)与 MongoDB(文档型数据库)代表了数据存储的两种核心范式。TiDB 继承了关系型数据库的严谨数据模型和强事务保证,MongoDB 则以灵活的文档模型和敏捷开发著称。本文从数据模型、查询能力、事务支持、扩展方式和适用场景五个维度进行系统对比,帮助技术团队根据业务特征选择最合适的存储方案。
本文适合谁:正在评估关系型与文档型数据库选型的技术架构师、后端负责人,以及需要同时处理结构化和非结构化数据的系统设计师。
一、数据模型对比
1.1 核心数据模型差异
| 维度 | TiDB | MongoDB |
|---|---|---|
| 数据模型 | 关系型(表 + 行 + 列) | 文档型(集合 + 文档/BSON) |
| Schema 策略 | 固定 Schema(DDL 定义) | 动态 Schema(灵活文档结构) |
| 数据格式 | 关系型表格 | JSON/BSON 文档 |
| 嵌套结构 | 需要关联表(JOIN) | 原生支持嵌套文档 |
| 数据类型 | SQL 标准数据类型 | 丰富的 BSON 类型(含数组、日期、二进制等) |
| 数据约束 | 强约束(NOT NULL、UNIQUE、CHECK) | 弱约束(Schema Validation 可选) |
| 多态数据 | 需要额外列或关联表 | 原生支持(同一集合不同结构) |
1.2 数据模型示例对比
-- TiDB:关系型建模(用户 + 订单,通过外键关联)
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_RANDOM,
name VARCHAR(100) NOT NULL,
email VARCHAR(200) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_email (email)
);
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_RANDOM,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
status VARCHAR(20) NOT NULL,
items JSON, -- 订单明细(JSON 类型)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id)
);
// MongoDB:文档型建模(用户 + 订单可内嵌或独立集合)
// 独立集合方式
db.users.insertOne({
name: "张三",
email: "zhangsan@example.com",
createdAt: new Date(),
tags: ["VIP", "活跃用户"] // 灵活字段
});
db.orders.insertOne({
userId: ObjectId("..."),
amount: NumberDecimal("150.00"),
status: "completed",
items: [
{ productId: "P001", name: "商品A", price: 50, qty: 2 },
{ productId: "P002", name: "商品B", price: 50, qty: 1 }
],
createdAt: new Date()
});
// 内嵌方式(订单直接嵌入用户文档)
db.users.insertOne({
name: "张三",
email: "zhangsan@example.com",
orders: [
{ amount: 150, status: "completed", items: [...] }
]
});
1.3 数据模型选型要点
| 场景 | 推荐 TiDB | 推荐 MongoDB |
|---|---|---|
| 数据结构固定、关系明确 | 强关系约束更安全 | Schema 过度灵活反而增加风险 |
| 数据结构多变、频繁迭代 | Schema 变更需要 DDL 迁移 | 动态 Schema 天然适配 |
| 强数据一致性要求 | 完整约束 + 事务保证 | Schema Validation 可选,但不如 SQL 严格 |
| 复杂嵌套文档 | JSON 类型支持,但查询不如原生文档灵活 | 原生嵌套查询能力更强 |
| 多对多关系 | JOIN 高效处理 | 需要 denormalize 或 $lookup |
二、查询能力对比
2.1 查询能力矩阵
| 查询能力 | TiDB | MongoDB |
|---|---|---|
| 点查(主键) | 优秀(B+ Tree) | 优秀(B+ Tree / Hash) |
| 范围查询 | 优秀(索引支持) | 良好(索引支持) |
| 多条件 AND/OR | 优秀(多列索引 + 优化器) | 良好(复合索引) |
| JOIN | 原生支持(优化器自动选择路径) | $lookup 聚合管道(性能有限) |
| 子查询 | 完整支持 | 支持($expr、聚合子查询) |
| 窗口函数 | 完整支持 | 5.0+ 支持($setWindowFields) |
| CTE | 支持 | 支持($lookup with pipeline) |
| 全文检索 | 内置全文索引(有限) | Atlas Search / Text Index |
| 地理空间查询 | 支持(MySQL 空间函数) | GeoJSON 原生支持(2dsphere) |
| 聚合管道 | GROUP BY + 窗口函数 | aggregation pipeline(丰富但性能波动) |
| JSON 查询 | JSON 函数(->、->>) | 原生文档路径查询 |
2.2 JOIN 查询对比
-- TiDB:原生 JOIN(优化器自动选择最佳执行计划)
SELECT
u.name,
u.email,
o.id AS order_id,
o.amount,
o.status,
o.created_at
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.id = 1001
ORDER BY o.created_at DESC;
-- 单次查询,执行时间 < 1ms
// MongoDB:$lookup 实现 JOIN
db.users.aggregate([
{ $match: { _id: ObjectId("...") } },
{
$lookup: {
from: "orders",
localField: "_id",
foreignField: "userId",
as: "user_orders"
}
},
{ $unwind: "$user_orders" },
{ $sort: { "user_orders.createdAt": -1 } },
{
$project: {
name: 1,
email: 1,
orderId: "$user_orders._id",
amount: "$user_orders.amount",
status: "$user_orders.status"
}
}
]);
// 聚合管道方式,性能不如 TiDB 原生 JOIN
2.3 JSON/文档查询对比
-- TiDB:JSON 函数查询
SELECT
id,
JSON_EXTRACT(items, '$[0].name') AS first_item,
JSON_LENGTH(items) AS item_count
FROM orders
WHERE JSON_CONTAINS(items, '"P001"', '$[*].productId');
-- TiDB 5.x+:JSON Table Value Function
SELECT jt.product_id, jt.name, jt.qty
FROM orders,
JSON_TABLE(items, '$[*]' COLUMNS (
product_id VARCHAR(20) PATH '$.productId',
name VARCHAR(100) PATH '$.name',
qty INT PATH '$.qty'
)) AS jt
WHERE id = 1001;
// MongoDB:原生文档路径查询
db.orders.find(
{ "items.productId": "P001" },
{ "items.$": 1 }
);
// 原生路径表达式,语法简洁
三、事务支持对比
| 事务指标 | TiDB | MongoDB |
|---|---|---|
| 事务模型 | 分布式事务(Percolator + 2PC) | 多文档事务(4.0+,基于两阶段提交) |
| 隔离级别 | RC、RR、Serializable | Snapshot Isolation(快照隔离) |
| 一致性保证 | 线性一致性(Raft) | 因部署模式而异(因果一致性/线性一致性) |
| 跨集合事务 | 天然支持(跨表事务) | 4.0+ 支持跨集合事务(性能有开销) |
| 事务大小限制 | 建议 < 100MB | 16MB 文档大小限制影响事务范围 |
| 分布式事务延迟 | 跨 Region 有网络开销 | 分片事务有额外开销 |
| 事务性能 | OLTP 场景优秀 | 多文档事务性能比单文档操作低 30-50% |
事务使用对比
-- TiDB:分布式事务(应用无感知)
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1001;
UPDATE accounts SET balance = balance + 100 WHERE id = 2002;
INSERT INTO transactions (from_id, to_id, amount) VALUES (1001, 2002, 100);
COMMIT;
// MongoDB:多文档事务(需要显式 session)
const session = client.startSession();
try {
session.startTransaction();
await db.accounts.updateOne(
{ _id: 1001 },
{ $inc: { balance: -100 } },
{ session }
);
await db.accounts.updateOne(
{ _id: 2002 },
{ $inc: { balance: 100 } },
{ session }
);
await db.transactions.insertOne(
{ fromId: 1001, toId: 2002, amount: 100 },
{ session }
);
await session.commitTransaction();
} finally {
session.endSession();
}
四、扩展方式对比
| 扩展维度 | TiDB | MongoDB |
|---|---|---|
| 水平扩展方式 | 增加节点,PD 自动调度数据 | 增加分片(Shard),Balancer 自动均衡 |
| 分片策略 | 自动(Range 分裂) | Hash / Range / 自定义分片键 |
| 扩展透明度 | 对应用完全透明 | 大部分透明(分片键选择影响性能) |
| 弹性扩缩容 | 在线扩缩容,秒级生效 | 在线扩缩容,分钟级生效 |
| 数据均衡 | PD 调度,Region 自动迁移 | Config Server + Balancer |
| 多数据中心 | 原生跨 Region 部署 | Zone/Shard 策略 + Cross-DC 复制 |
| 存储计算分离 | 是(计算/存储独立扩展) | 部分支持(Shared 策略可配置) |
五、适用场景分析
5.1 推荐使用 TiDB 的场景
| 场景 | 原因 |
|---|---|
| 金融交易、账务系统 | 强事务、强一致性、数据约束 |
| ERP/CRM/OA 系统 | 关系模型天然匹配、复杂 JOIN 需求 |
| 电商订单与库存管理 | 事务一致性 + 实时查询 + 分析 |
| SaaS 多租户系统 | 强隔离 + 灵活权限 + HTAP |
| 实时报表与 BI | HTAP 一体化,无需额外分析系统 |
5.2 推荐使用 MongoDB 的场景
| 场景 | 原因 |
|---|---|
| 内容管理系统(CMS) | 灵活 Schema,内容结构多变 |
| 物联网数据采集 | 多态设备数据,字段不固定 |
| 用户画像/行为日志 | 嵌套文档,灵活标签 |
| 实时分析中间层 | 高写入吞吐 + 灵活查询 |
| 移动应用后端 | Schema 灵活 + 开发敏捷 |
5.3 混合使用场景
在实际系统中,TiDB 与 MongoDB 可以各司其职:
混合架构:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 业务系统 │────▶│ TiDB │ │ MongoDB │
└──────────┘ │核心业务数据│ │灵活文档数据│
│(订单/账务)│ │(日志/画像)│
└──────────┘ └──────────┘
│
▼
搜索引擎
缓存层
FAQ
Q1:TiDB 的 JSON 类型能否替代 MongoDB 的文档存储能力?
TiDB 支持原生 JSON 数据类型和 JSON 函数,可以存储和查询半结构化数据。但在以下方面不如 MongoDB:嵌套文档的灵活查询语法、原生文档更新操作符($push/$pull/$set)、多态文档的存储效率。如果你的数据以非结构化文档为主,MongoDB 仍然是更合适的选择。
Q2:MongoDB 的事务性能能否满足核心交易场景?
MongoDB 从 4.0 开始支持多文档事务,在单分片场景下事务性能表现良好。但在跨分片分布式事务场景下,性能开销显著增大(约 30-50%),且快照隔离级别不如 TiDB 的 RR 级别严格。对于金融核心交易等对事务性能和一致性要求极高的场景,TiDB 是更稳健的选择。
Q3:TiDB 能否存储非结构化数据?
TiDB 通过 JSON 数据类型可以存储非结构化数据,单个 JSON 列最大支持 1GB(由 max_allowed_packet 控制)。同时 TiDB 提供 JSON Table Value Function,可以将 JSON 数据展开为关系型表进行查询。但 TiDB 的 JSON 能力是关系型数据库的扩展,不是核心设计,大规模 JSON 数据的查询性能和灵活性不如 MongoDB。
Q4:从 MongoDB 迁移到 TiDB 需要注意什么?
迁移需要注意以下关键问题:Schema 设计转换(从文档模型转为关系模型)、嵌套文档的展平、$lookup 查询转为 SQL JOIN、灵活字段的处理(可使用 JSON 列保留灵活性)、MongoDB 特有操作符的替代(如 $push/$pull 改为 SQL UPDATE)。建议使用 TiDB 提供的迁移工具进行数据导入,并充分测试查询兼容性。
总结
TiDB 与 MongoDB 分属关系型与文档型数据库的代表性产品,各自在擅长的领域具有不可替代的优势。TiDB 在强事务、复杂关系查询、数据一致性约束方面表现卓越,适合核心业务系统;MongoDB 在 Schema 灵活性、嵌套文档处理、快速迭代开发方面优势突出,适合内容管理、物联网、日志分析等场景。
选择的关键不在于"哪个更好",而在于业务数据的特征和需求。如果数据以固定结构的关系型数据为主,需要强事务保证和复杂查询能力,TiDB 是更合适的选择。如果数据以多变的非结构化文档为主,需要灵活的 Schema 和快速的迭代能力,MongoDB 更有优势。在复杂业务系统中,两者可以配合使用。
下一步行动
- 试用 TiDB:体验 TiDB 的关系型分布式能力,验证 SQL 兼容性和 JSON 数据类型支持。
- 获取结构化数据解决方案:了解 TiDB 在金融、电商、SaaS 等结构化数据密集型行业的最佳实践。
- 申请 POC 测试:提供您的数据模型,获取专属的 TiDB POC 测试环境和迁移评估报告。