MongoDB vs MySQL:区别与应用场景
1. 数据模型
MongoDB
- 非关系型(NoSQL),存储的是 JSON 格式 的 文档(Document)。
- 数据结构灵活,不要求每个文档有相同的字段,适合存储 动态变化的数据。
例子:
存储用户信息(user
集合):
{"name": "张三","age": 25,"hobbies": ["篮球", "编程"],"address": { "city": "北京", "zip": "100000" }
}
- 没有固定的表结构,可以随时增加新字段,如
hobbies
这个数组字段。
MySQL
- 关系型数据库(RDBMS),数据存储在 表(Table) 里,数据结构固定。
- 表结构必须事先定义,不能随意增加字段。
例子:
创建 users
表:
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),age INT,city VARCHAR(50),zip VARCHAR(10)
);
插入数据:
INSERT INTO users (name, age, city, zip) VALUES ("张三", 25, "北京", "100000");
- 必须定义所有字段,如果后续想存
hobbies
,就需要 修改表结构。
提炼要点
MongoDB | MySQL | |
---|---|---|
数据存储 | JSON 文档(BSON) | 表(行 + 列) |
结构 | 无固定模式(Schema-less) | 结构固定(Schema-based) |
灵活性 | 可以存储不同结构的数据 | 需要事先定义表结构 |
2. 查询语言
MongoDB
- 不使用 SQL,查询基于 JavaScript 语法。
- 无需 JOIN,数据通常以嵌套文档形式存储,避免多表查询的性能问题。
查询用户年龄大于 20 岁的文档:
db.users.find({ "age": { $gt: 20 } })
MySQL
- 使用 SQL(Structured Query Language),标准化查询语言。
- 支持复杂查询和多表 JOIN。
查询用户年龄大于 20 岁的数据:
SELECT * FROM users WHERE age > 20;
提炼要点
MongoDB | MySQL | |
---|---|---|
查询语言 | MongoDB 查询语法 | SQL |
多表查询 | 依靠文档嵌套存储,减少 JOIN | 通过 JOIN 关联多个表 |
查询灵活性 | 适合非结构化数据 | 适合结构化数据 |
3. 数据一致性与事务
MongoDB
- 默认是最终一致性(数据可能有短暂的不同步)。
- MongoDB 4.0+ 支持事务,但性能比 SQL 事务 稍逊。
示例:原子更新文档
db.users.updateOne({ "name": "张三" }, { $set: { "age": 26 } })
- 仅更新匹配的文档,不影响其他数据。
MySQL
- 提供强一致性,符合 ACID 原则(原子性、一致性、隔离性、持久性)。
- 事务管理完善,支持
COMMIT
和ROLLBACK
。
示例:事务操作
START TRANSACTION;
UPDATE users SET age = 26 WHERE name = "张三";
COMMIT;
- 如果操作失败,可
ROLLBACK
取消更改,保证数据一致性。
提炼要点
MongoDB | MySQL | |
---|---|---|
数据一致性 | 默认最终一致性 | 强一致性(ACID) |
事务支持 | 4.0+ 版本支持多文档事务 | 原生支持事务 |
4. 扩展性
MongoDB
- 水平扩展(Sharding):数据可以分布到 多个服务器 上,提高处理能力。
- 适合大规模数据,比如 社交平台、大数据存储。
MySQL
- 主要依赖垂直扩展(提升单台服务器性能,如增加内存、CPU)。
- 水平扩展较复杂,通常使用 分库分表、读写分离 来优化。
提炼要点
MongoDB | MySQL | |
---|---|---|
扩展方式 | 水平扩展(Sharding) | 垂直扩展(升级服务器) |
适用场景 | 大规模数据存储 | 传统业务应用 |
5. 适用场景
MongoDB 适用场景
✅ 动态数据存储(如社交平台、内容管理系统)
✅ 大数据存储与实时分析(日志、物联网数据)
✅ 快速开发(无需预定义表结构)
示例:社交媒体平台
- 用户帖子包含 文本、图片、视频、点赞、评论 等,格式复杂且变化快,MongoDB 更适合。
MySQL 适用场景
✅ 高事务要求(如银行、支付系统)
✅ 数据结构固定(如企业 ERP、CRM 系统)
✅ 复杂查询与报表分析(多表 JOIN)
示例:银行系统
- 账户交易需要 强一致性 和 事务支持,MySQL 更适合。
总结
MongoDB | MySQL | |
---|---|---|
适合场景 | 大数据、动态数据、实时分析 | 事务、数据完整性要求高 |
示例 | 社交平台、日志存储 | 银行、ERP、CRM |
最终总结
维度 | MongoDB | MySQL |
---|---|---|
数据存储 | JSON 文档(BSON) | 表(行 + 列) |
查询语言 | Mongo 查询语法(基于 JavaScript) | SQL |
事务支持 | 4.0+ 支持事务,但不如 SQL 强 | 支持 ACID 事务 |
扩展性 | 水平扩展(Sharding) | 垂直扩展(升级服务器) |
适合场景 | 大数据、内容管理、社交平台 | 事务处理、金融系统 |
选择建议
- 如果是 高并发、大数据、非结构化存储,✅ MongoDB 更合适。
- 如果是 事务、数据一致性要求高,✅ MySQL 更合适。
1. 什么是字符集?
字符集(Character Set)决定了 数据库如何存储、读取和表示字符。如果字符集选择不当,可能会导致:
- 存储占用不合理(存储空间变大或变小)。
- 数据查询性能下降(字符编码转换耗时)。
- 数据乱码(字符存储和解析方式不一致)。
2. 常见 MySQL 字符集
字符集 | 每个字符最大占用字节 | 特点 |
---|---|---|
GBK | 2 | 适合中文,存储空间比 UTF-8 少,但不支持特殊符号和国际化。 |
UTF-8 | 3 | 国际通用字符集,支持多语言,适合中英文混合。 |
latin1 | 1 | MySQL 早期默认字符集,仅支持英文。 |
utf8mb4 | 4 | 完全兼容 UTF-8,支持 Emoji 表情和特殊符号。 |
3. 字符集选择规则
✅ 外贸、国际业务(多语言) → utf8mb4
(保证兼容性)
✅ 国内中文网站 → GBK
(存储效率高)
✅ 纯英文数据 → latin1
(存储空间最小,性能好)
4. 影响示例
(1)字符存储占用
存储 "你好"
:
- GBK:2 × 2 = 4 字节
- UTF-8:3 × 2 = 6 字节
- utf8mb4:4 × 2 = 8 字节
示例:创建 UTF-8 表
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) CHARACTER SET utf8mb4
);
(2)乱码问题
如果客户端和数据库字符集不同,可能会出现乱码:
SHOW VARIABLES LIKE 'character%';
解决方法:
SET NAMES utf8mb4;
MySQL 字符集的设置层级
在 MySQL 中,字符集可以在 不同层级 进行设置,分别是:
- 服务器级(Server)
- 数据库级(Database)
- 表级(Table)
- 列级(Column)
1. 作用范围
级别 | 影响范围 | 设置方式 |
---|---|---|
服务器级(Server) | 整个 MySQL 服务器 | my.cnf 配置文件 |
数据库级(Database) | 该数据库的所有表 | CREATE DATABASE |
表级(Table) | 该表的所有列 | CREATE TABLE |
列级(Column) | 仅影响该列 | VARCHAR(50) CHARACTER SET utf8mb4 |
2. 具体示例
(1)服务器级
默认字符集设置(修改 my.cnf
配置文件):
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
作用:
(2)数据库级
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
作用:
- 影响新建的 表默认字符集,但不会修改已有表。
- 仅影响 新建的表,不会影响已有表的数据存储格式。
(3)表级
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50)
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
作用:
- 该表的 所有列 默认使用
utf8mb4
,但可以在列级别单独更改字符集。
(4)列级
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) CHARACTER SET gbk, -- 该列为 GBKemail VARCHAR(100) CHARACTER SET utf8mb4 -- 该列为 UTF8MB4
);
作用:
- 该表的
name
字段用GBK
存储,而email
字段用UTF8MB4
存储。
3. 重要结论
4. 修改已有表的字符集
如果想修改已有数据的字符集:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4;
注意: 这个操作会导致数据库重新编码,可能会有 数据损坏 或 查询性能下降,需要 谨慎测试 后再操作。
数据库三范式(举例+要点)
范式(Normal Form, NF) 是数据库设计的一套规则,目的是 减少数据冗余,提高数据一致性。
三范式(1NF、2NF、3NF)是数据库设计的基本要求,满足 越高范式 的数据库,数据重复率越低,但查询可能变复杂。
第一范式(1NF)—— 列的“原子性”
要求:
- 数据必须是“最小单元”,不能再拆分。
- 表中每一列只能存储单一值,不能有 数组、列表、逗号分隔的多个值。
✅ 符合 1NF(原子性数据):
ID | 姓名 | 电话 |
---|---|---|
1 | 张三 | 13800138000 |
2 | 李四 | 13900139000 |
❌ 不符合 1NF(多值存储):
ID | 姓名 | 电话 |
---|---|---|
1 | 张三 | 13800138000, 13900239000 |
2 | 李四 | 13900139000 |
❌ 问题: 电话
列含多个值,查询 13900139000
属于谁时,需要拆分字符串,影响查询效率。
✅ 解决办法:
如果一个人有多个手机号,就拆成多行或 创建新表:
ID | 姓名 | 电话 |
---|---|---|
1 | 张三 | 13800138000 |
1 | 张三 | 13900239000 |
第二范式(2NF)——“消除部分依赖”
要求:
- 必须先满足 1NF
- 所有列必须完全依赖于主键,不能“部分依赖”
- 适用于复合主键的情况(主键由多个列组成)
举例:
❌ 不符合 2NF:
订单ID(主键) | 商品ID(主键) | 商品名称 | 订单日期 |
---|---|---|---|
1001 | A1 | 苹果 | 2024-03-01 |
1001 | A2 | 香蕉 | 2024-03-01 |
❌ 问题:
商品名称
只依赖于商品ID
,但和订单ID
没关系,属于 “部分依赖”。- 如果同一个商品出现在多个订单中,商品名称就会重复,导致冗余!
✅ 解决办法:
拆分为两张表:
- 订单表(去掉商品名称,只存
订单ID
和订单日期
) - 商品表(存
商品ID
和商品名称
) - 订单-商品关联表(订单ID + 商品ID 作为联合主键)
订单ID(主键) | 订单日期 |
---|---|
1001 | 2024-03-01 |
商品ID(主键) | 商品名称 |
---|---|
A1 | 苹果 |
A2 | 香蕉 |
订单ID | 商品ID |
---|---|
1001 | A1 |
1001 | A2 |
✅ 这样,商品信息只存一份,避免冗余!
第三范式(3NF)——“消除传递依赖”
要求:
- 必须先满足 2NF
- 非主键列不能依赖于其他非主键列
- 即:所有非主属性只能依赖主键,不能依赖其他字段。
举例
❌ 不符合 3NF:
学号(主键) | 姓名 | 院系 | 院系地址 |
---|---|---|---|
1001 | 张三 | 计算机系 | A栋201 |
1002 | 李四 | 计算机系 | A栋201 |
❌ 问题:
院系地址
依赖于院系
,但和学号
没直接关系,属于 “传递依赖”。- 如果计算机系的地址变了,需要修改所有该系的学生数据,容易出错!
✅ 解决办法:
拆分表,建立 院系表:
学号(主键) | 姓名 | 院系 |
---|---|---|
1001 | 张三 | 计算机系 |
1002 | 李四 | 计算机系 |
院系(主键) | 院系地址 |
---|---|
计算机系 | A栋201 |
这样,如果院系地址变了,只需要修改 院系表
,避免数据不一致。
最终总结
范式 | 要求 | 解决的问题 |
---|---|---|
1NF | 列是原子值,不能存多个值 | 不能在一列存多个数据,避免拆分字符串查询 |
2NF | 列必须完全依赖于主键 | 不能部分依赖,避免数据冗余 |
3NF | 不能有“传递依赖” | 非主键列只能依赖主键,避免数据重复 |
满足三范式后,数据库更规范,数据更一致,但查询可能变复杂。
在实际项目中,会在范式和性能之间折中,适当 反范式(Denormalization) 以提升查询速度。
InnoDB 与 MyISAM 区别
MySQL 提供了多种 存储引擎,最常见的就是 InnoDB 和 MyISAM。它们的主要区别体现在 事务支持、锁机制、性能、缓存机制等 方面。
1. 事务支持
事务(Transaction) 是 一组操作的集合,要么全部执行,要么全部不执行,保证数据一致性(ACID)。
✅ InnoDB 支持事务,可以 ROLLBACK
(回滚)数据。
❌ MyISAM 不支持事务,一旦执行 INSERT
、UPDATE
、DELETE
,就无法撤销。
📌 举例:
-- InnoDB 支持事务
START TRANSACTION;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
COMMIT; -- 事务提交
如果其中一个 UPDATE
失败:
ROLLBACK; -- 撤销所有修改
🔹 如果是 MyISAM,即使 UPDATE
失败,也无法回滚,导致数据可能出错。
2. 锁机制
✅ InnoDB 使用 行锁(Row Lock),即只锁住操作的那一行数据,并发性能高。
❌ MyISAM 使用 表锁(Table Lock),即使修改一行,也会锁住整个表,并发性能较低。
📌 举例:
-- InnoDB(行锁):多个线程可以同时操作不同的行
UPDATE users SET name = 'Alice' WHERE id = 1;-- MyISAM(表锁):一个操作会锁住整个表,其他线程必须等待
UPDATE users SET name = 'Bob' WHERE id = 2;
🔹 高并发场景(如支付、订单系统)用 InnoDB 更合适。
3. MVCC(多版本并发控制)
✅ InnoDB 支持 MVCC,能在不加锁的情况下进行并发读写,提升性能。
❌ MyISAM 不支持 MVCC,每次查询都要等待表解锁。
📌 举例:
在 InnoDB 里,一个事务可以读到自己开始时的数据,而不受其他事务影响:
-- 事务 A 读取数据
SELECT balance FROM accounts WHERE id = 1;-- 事务 B 修改数据
UPDATE accounts SET balance = balance - 500 WHERE id = 1;-- 事务 A 仍然可以看到未修改前的旧数据
SELECT balance FROM accounts WHERE id = 1;
🔹 适用于高并发读取的场景,如社交平台的帖子浏览。
4. 外键支持
✅ InnoDB 支持外键,可以保证数据一致性。
❌ MyISAM 不支持外键,只能通过应用程序保证数据完整性。
📌 举例:
-- InnoDB:定义外键
CREATE TABLE orders (id INT PRIMARY KEY,user_id INT,FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
🔹 如果删除 users
表中的用户,orders
里对应的订单也会自动删除(级联删除)。
🔹 MyISAM 不支持这种外键约束,可能导致数据不一致。
5. 索引
✅ InnoDB 使用 聚簇索引(Clustered Index),主键索引和数据存储在一起,查询主键时性能高。
❌ MyISAM 使用 非聚簇索引(Non-Clustered Index),索引和数据分开存储,查询主键时需要两次访问磁盘。
📌 举例:
-- InnoDB(聚簇索引)
SELECT * FROM users WHERE id = 1;
🔹 InnoDB 的主键索引直接定位到数据,查询快。
🔹 MyISAM 先通过索引找到数据位置,再去查询数据,查询慢。
6. 读写性能
✅ MyISAM 适合读多写少的场景(如日志、文章存储)。
✅ InnoDB 适合读写均衡、高并发、事务性强的应用(如支付、订单、银行系统)。
场景 | 适合引擎 |
---|---|
论坛、日志、统计 | MyISAM |
交易、支付、订单 | InnoDB |
高并发网站 | InnoDB |
7. 其他区别
特点 | InnoDB ✅ | MyISAM ❌ |
---|---|---|
事务 | 支持 | 不支持 |
外键 | 支持 | 不支持 |
锁机制 | 行锁 | 表锁 |
MVCC | 支持 | 不支持 |
索引存储 | 聚簇索引 | 非聚簇索引 |
全文索引 | MySQL 5.6+ 支持 | 支持 |
崩溃恢复 | 支持 | 不支持 |
数据存储 | 不保存行数 | 保存行数 |
读写场景 | 读写均衡 | 读多写少 |
总结
- InnoDB 适合 高并发、事务场景(如订单、支付)。
- MyISAM 适合 查询多、写入少的场景(如日志、统计)。
- 实际应用中,一般推荐使用 InnoDB,除非有特殊需求(如超大规模的只读数据)。
https://github.com/0voice