【MySQL】与MongoDB的区别,字符集,三范式,存储引擎InnoDB、MyISAM

MongoDB vs MySQL:区别与应用场景


1. 数据模型

MongoDB

  • 非关系型(NoSQL) ,存储的是 JSON 格式文档(Document)
  • 数据结构灵活 ,不要求每个文档有相同的字段,适合存储 动态变化的数据

例子:

存储用户信息(user 集合):

json 复制代码
{
  "name": "张三",
  "age": 25,
  "hobbies": ["篮球", "编程"],
  "address": { "city": "北京", "zip": "100000" }
}
  • 没有固定的表结构 ,可以随时增加新字段,如 hobbies 这个数组字段。

MySQL

  • 关系型数据库(RDBMS) ,数据存储在 表(Table) 里,数据结构固定。
  • 表结构必须事先定义,不能随意增加字段。

例子:

创建 users 表:

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50),
    age INT,
    city VARCHAR(50),
    zip VARCHAR(10)
);

插入数据:

sql 复制代码
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 岁的文档:

javascript 复制代码
db.users.find({ "age": { $gt: 20 } })

MySQL

  • 使用 SQL(Structured Query Language),标准化查询语言。
  • 支持复杂查询和多表 JOIN

查询用户年龄大于 20 岁的数据:

sql 复制代码
SELECT * FROM users WHERE age > 20;

提炼要点

MongoDB MySQL
查询语言 MongoDB 查询语法 SQL
多表查询 依靠文档嵌套存储,减少 JOIN 通过 JOIN 关联多个表
查询灵活性 适合非结构化数据 适合结构化数据

3. 数据一致性与事务

MongoDB

  • 默认是最终一致性(数据可能有短暂的不同步)。
  • MongoDB 4.0+ 支持事务 ,但性能比 SQL 事务 稍逊

示例:原子更新文档

javascript 复制代码
db.users.updateOne({ "name": "张三" }, { $set: { "age": 26 } })
  • 仅更新匹配的文档,不影响其他数据

MySQL

  • 提供强一致性,符合 ACID 原则(原子性、一致性、隔离性、持久性)。
  • 事务管理完善 ,支持 COMMITROLLBACK

示例:事务操作

sql 复制代码
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)字符存储占用

存储 "你好"

  • GBK2 × 2 = 4 字节
  • UTF-83 × 2 = 6 字节
  • utf8mb44 × 2 = 8 字节

示例:创建 UTF-8 表

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) CHARACTER SET utf8mb4
);

(2)乱码问题

如果客户端和数据库字符集不同,可能会出现乱码:

sql 复制代码
SHOW VARIABLES LIKE 'character%';

解决方法:

sql 复制代码
SET NAMES utf8mb4;

MySQL 字符集的设置层级

在 MySQL 中,字符集可以在 不同层级 进行设置,分别是:

  1. 服务器级(Server)
  2. 数据库级(Database)
  3. 表级(Table)
  4. 列级(Column)

1. 作用范围

级别 影响范围 设置方式
服务器级(Server) 整个 MySQL 服务器 my.cnf 配置文件
数据库级(Database) 该数据库的所有表 CREATE DATABASE
表级(Table) 该表的所有列 CREATE TABLE
列级(Column) 仅影响该列 VARCHAR(50) CHARACTER SET utf8mb4

2. 具体示例

(1)服务器级

默认字符集设置(修改 my.cnf 配置文件):

ini 复制代码
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

作用:

  • 影响新建的 数据库默认字符集,但不会修改已有数据库。
  • 服务器重启后生效。

(2)数据库级

sql 复制代码
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

作用:

  • 影响新建的 表默认字符集,但不会修改已有表。
  • 仅影响 新建的表,不会影响已有表的数据存储格式。

(3)表级

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50)
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

作用:

  • 该表的 所有列 默认使用 utf8mb4,但可以在列级别单独更改字符集。

(4)列级

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) CHARACTER SET gbk,  -- 该列为 GBK
    email VARCHAR(100) CHARACTER SET utf8mb4  -- 该列为 UTF8MB4
);

作用:

  • 该表的 name 字段用 GBK 存储,而 email 字段用 UTF8MB4 存储。

3. 重要结论

  • 优先级:列级 > 表级 > 数据库级 > 服务器级
  • 修改数据库字符集 仅影响 新建的表,不会更改已有表的数据存储。
  • 修改表或列的字符集 可能会 影响已有数据(可能会导致数据转换或乱码)。

4. 修改已有表的字符集

如果想修改已有数据的字符集:

sql 复制代码
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 没关系 ,属于 "部分依赖"
  • 如果同一个商品出现在多个订单中,商品名称就会重复,导致冗余!

✅ 解决办法:

拆分为两张表:

  1. 订单表(去掉商品名称,只存 订单ID订单日期
  2. 商品表(存 商品ID商品名称
  3. 订单-商品关联表(订单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 不支持事务 ,一旦执行 INSERTUPDATEDELETE,就无法撤销。

📌 举例:

sql 复制代码
-- InnoDB 支持事务
START TRANSACTION;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
COMMIT;  -- 事务提交

如果其中一个 UPDATE 失败:

sql 复制代码
ROLLBACK;  -- 撤销所有修改

🔹 如果是 MyISAM ,即使 UPDATE 失败,也无法回滚,导致数据可能出错。


2. 锁机制

InnoDB 使用 行锁(Row Lock) ,即只锁住操作的那一行数据 ,并发性能高。

MyISAM 使用 表锁(Table Lock)即使修改一行,也会锁住整个表,并发性能较低。

📌 举例:

sql 复制代码
-- 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 里,一个事务可以读到自己开始时的数据,而不受其他事务影响:

sql 复制代码
-- 事务 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 不支持外键,只能通过应用程序保证数据完整性。

📌 举例:

sql 复制代码
-- 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),索引和数据分开存储,查询主键时需要两次访问磁盘。

📌 举例:

sql 复制代码
-- 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

相关推荐
Dann Hiroaki32 分钟前
文献分享: ConstBERT固定数目向量编码文档
数据库·机器学习·自然语言处理·nlp
黑风风1 小时前
探索 Ubuntu 中的 Hostname 配置与管理
数据库·ubuntu·php
rkmhr_sef2 小时前
MyBatis-Plus 自定义 SQL 和复杂查询
数据库·sql·mybatis
Craaaayon2 小时前
Docker基础-自定义镜像与容器网络
java·运维·网络·数据库·后端·docker·容器
茂桑2 小时前
记录一次Spring事务失效导致的生产问题
数据库
天地风雷水火山泽3 小时前
二百八十五、华为云PostgreSQL——建分区表并设置主键
数据库·postgresql·华为云
IT程序媛-桃子3 小时前
Oracle连接满了,无法登录数据库,如何分析连接来源?
数据库·oracle
Watink Cpper3 小时前
[MySQL初阶]MySQL(3)表的约束
linux·运维·服务器·数据库·mysql·表的约束
然子而3 小时前
苍穹外卖学习笔记(跳过微信支付)
java·spring boot·git·学习·mysql·maven·mybatis
Craaaayon4 小时前
Docker基础-常见命令与数据卷
java·数据库·后端·mysql·docker·容器·eureka