一、关系型数据库概述
关系型数据库(RDBMS)基于关系模型,数据以表(Table)的形式组织,表之间有明确的关联关系,通过 SQL(Structured Query Language)进行操作。
常见产品:MySQL、PostgreSQL、Oracle、SQL Server、SQLite。
1 2 3 4 5 6 7 8 9 10 11
| 核心特征: ┌──────────────┐ ┌──────────────┐ │ users 表 │ │ orders 表 │ ├──────────────┤ ├──────────────┤ │ id (PK) │◄─────│ user_id (FK) │ │ name │ │ product │ │ email │ │ amount │ │ created_at │ │ created_at │ └──────────────┘ └──────────────┘
数据通过外键关联,通过 JOIN 查询。
|
关系型数据库的核心能力
1 2 3 4 5
| ├── 结构化 Schema:必须先定义表结构再写入数据 ├── ACID 事务:保证数据一致性(银行转账、订单扣库存) ├── 关系与 JOIN:通过外键关联多表查询 ├── SQL 标准:统一的查询语言,强大的聚合和过滤 └── 成熟生态:二十多年的工具链和社区积累
|
二、非关系型数据库概述
非关系型数据库(NoSQL — Not Only SQL)放弃或简化了关系模型,以换取更高的性能、可伸缩性和灵活性。
常见产品:MongoDB(文档型)、Redis(键值型)、HBase(列族型)、Neo4j(图型)。
主要分类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 文档型(Document Store) 代表:MongoDB、CouchDB 数据以 JSON/BSON 文档存储,支持嵌套结构 适用:内容管理、日志、配置
键值型(Key-Value Store) 代表:Redis、DynamoDB 数据以键值对存储,性能最高 适用:缓存、会话、计数器
列族型(Column Family) 代表:HBase、Cassandra 数据以列族存储,适合宽表 适用:时序数据、大数据分析
图数据库(Graph DB) 代表:Neo4j、ArangoDB 数据以节点和边存储 适用:社交关系、推荐系统
|
三、核心对比
数据模型
1 2 3 4 5 6 7 8 9 10 11 12
| 关系型: ┌──────────┬──────────┐ │ name │ skills │ 扁平结构,需拆多表 ├──────────┼──────────┤ │ Alice │ cooking │ │ Alice │ dancing │ ← 用户和技能拆分在不同表 │ Bob │ reading │ └──────────┴──────────┘
文档型(MongoDB): { name: "Alice", skills: ["cooking", "dancing"] } ← 嵌入式数组 { name: "Bob", skills: ["reading"] }
|
Schema(模式)
| 关系型 | 非关系型(文档型) |
|---|
| Schema | 严格,先定义后写入 | 灵活,同集合可不同结构 |
| 修改字段 | ALTER TABLE 可能锁表 | 随时添加,不影响旧数据 |
| 迁移 | 需手动执行 migration | 在代码层面处理兼容 |
1 2 3 4
| { name: "Alice", age: 25 } { name: "Bob" } { name: "Charlie", phone: "123" }
|
事务与一致性
| 特性 | 关系型(MySQL InnoDB) | 文档型(MongoDB) |
|---|
| ACID 事务 | ✅ 完整支持 | ✅ 4.0+ 支持多文档事务 |
| 隔离级别 | READ COMMITTED / REPEATABLE READ | snapshot 隔离 |
| 强一致性 | 默认 | 默认(primary 读写) |
| 最终一致性 | 不支持 | 副本集可配置 |
查询能力
1 2 3 4 5 6 7
| SELECT u.name, o.product, o.amount FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.age > 20 AND o.amount > 100 ORDER BY o.created_at DESC LIMIT 10;
|
1 2 3 4 5 6 7 8 9 10
| db.users.aggregate([ { $match: { age: { $gt: 20 } } }, { $lookup: { from: "orders", localField: "_id", foreignField: "userId", as: "orders" } }, { $unwind: "$orders" }, { $match: { "orders.amount": { $gt: 100 } } }, { $sort: { "orders.createdAt": -1 } }, { $limit: 10 }, { $project: { name: 1, "orders.product": 1, "orders.amount": 1 } }, ]);
|
伸缩性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 关系型: ┌───── 垂直扩展(Scale Up)─────┐ │ 增加单机 CPU/内存/磁盘 │ │ 简单但有限制(单机天花板) │ └──────────────────────────────┘ ┌───── 水平扩展(Scale Out)─────┐ │ 读写分离(主从复制) │ │ 分库分表(Sharding)实现复杂 │ └──────────────────────────────┘
文档型(MongoDB): ┌───── 水平扩展(天然支持)─────┐ │ 分片(Sharding)内置 │ │ 自动数据均衡 │ │ 对应用层透明 │ └──────────────────────────────┘
|
综合对比表
| 维度 | 关系型(MySQL) | 文档型(MongoDB) | 键值型(Redis) |
|---|
| 数据模型 | 表 + 行 + 列 | JSON 文档 | 键值对 |
| Schema | 严格 | 灵活 | 无 |
| 事务 | ACID | 4.0+ 多文档 | 有限 |
| JOIN | 原生支持 | $lookup | 不支持 |
| 索引 | B+ Tree | B+ Tree | 哈希 |
| 水平扩展 | 复杂(分库分表) | 原生分片 | 集群模式 |
| 典型场景 | 财务、ERP、CRM | 内容、日志、IoT | 缓存、会话 |
| 一致性偏好 | 强一致性 | 可调 | 最终一致性 |
四、CAP 定理与选型
CAP 定理
1 2 3 4 5 6 7 8
| C(Consistency)一致性:所有节点在同一时刻看到相同数据 A(Availability)可用性:每次请求都能获得非错响应 P(Partition Tolerance)分区容忍性:网络分区时系统仍能运行
定理:一个分布式系统最多只能同时满足两项。 ├── CP:放弃可用性,保证一致性(传统数据库) ├── AP:放弃一致性,保证可用性(很多 NoSQL) └── CA:现实中不存在(网络分区必然发生)
|
如何选择
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 选关系型(MySQL/PostgreSQL): ├── 数据结构稳定,不会频繁变化 ├── 需要复杂 JOIN 和聚合查询 ├── 事务强一致性要求高(金融、订单) └── 数据量可预估,单机可承受
选文档型(MongoDB): ├── 数据结构灵活,迭代频繁 ├── 需要嵌入式文档(如用户 + 地址) ├── 需要快速水平扩展 └── 读写性能优先于强一致性
选键值型(Redis): ├── 缓存、计数器、排行榜 ├── 需要微秒级响应时间 └── 数据结构简单
混合使用(最常见): ├── MySQL 存核心业务数据(订单、用户) ├── Redis 做缓存和会话 └── MongoDB 存日志、配置、内容
|
NoSQL 并非”不要 SQL”
1 2 3 4 5 6
| NoSQL 最初的含义是 "No SQL"(反对 SQL), 后来演变为 "Not Only SQL"(不仅仅是 SQL)。
实际上,MongoDB 的查询语言越来越像 SQL, 而 MySQL 8.0 也增加了 JSON 字段和文档存储支持。 两者在互相借鉴,而不是对立。
|
五、面试题
Q1: 关系型和非关系型数据库的区别
1 2 3 4 5 6
| 1. 数据模型:关系型用表和行,非关系型用文档/键值/图 2. Schema:关系型严格,非关系型灵活 3. 关联查询:关系型原生 JOIN,非关系型需 $lookup 或应用层关联 4. 事务:关系型 ACID 完整,非关系型支持有限 5. 扩展:关系型垂直扩展为主,非关系型原生水平扩展 6. 适用场景:关系型适合强一致性业务,非关系型适合灵活/高性能场景
|
Q2: 什么是反范式化设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 范式化(Normalization): 减少数据冗余,通过拆分表和关联来保持一致性。
反范式化(Denormalization): 允许冗余,将关联数据嵌入同一文档或表中, 以减少 JOIN 次数,提高读取性能。
MongoDB 天然倾向反范式化: { user: "Alice", orders: [{ product: "手机", amount: 5000 }] } 而不是拆成 users 和 orders 两张表再 JOIN。
取舍: 范式化 → 写入快、一致性高、无冗余 反范式化 → 读取快、减少 JOIN、更新需处理冗余
|
Q3: 什么时候用 MongoDB 什么时候用 MySQL
1 2 3 4 5 6 7 8 9 10 11
| 用 MySQL: ├── 电商订单系统(需要事务保证库存一致性) ├── 财务系统(ACID 高要求) ├── 复杂报表统计(多表 JOIN + 聚合) └── 数据结构稳定,不频繁变化
用 MongoDB: ├── 内容管理系统(不同文章类型字段不同) ├── 日志收集系统(灵活 Schema + 高写入吞吐) ├── IoT 设备数据(快速水平扩展) └── 原型阶段(快速迭代,字段频繁变化)
|