当前位置: 首页 > article >正文

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

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,就需要 修改表结构

提炼要点

MongoDBMySQL
数据存储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;

提炼要点

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

3. 数据一致性与事务

MongoDB

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

示例:原子更新文档

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

MySQL

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

示例:事务操作

START TRANSACTION;
UPDATE users SET age = 26 WHERE name = "张三";
COMMIT;
  • 如果操作失败,可 ROLLBACK 取消更改,保证数据一致性。

提炼要点

MongoDBMySQL
数据一致性默认最终一致性强一致性(ACID)
事务支持4.0+ 版本支持多文档事务原生支持事务

4. 扩展性

MongoDB

  • 水平扩展(Sharding):数据可以分布到 多个服务器 上,提高处理能力。
  • 适合大规模数据,比如 社交平台大数据存储

MySQL

  • 主要依赖垂直扩展(提升单台服务器性能,如增加内存、CPU)。
  • 水平扩展较复杂,通常使用 分库分表、读写分离 来优化。

提炼要点

MongoDBMySQL
扩展方式水平扩展(Sharding)垂直扩展(升级服务器)
适用场景大规模数据存储传统业务应用

5. 适用场景

MongoDB 适用场景

动态数据存储(如社交平台、内容管理系统)
大数据存储与实时分析(日志、物联网数据)
快速开发(无需预定义表结构)

示例:社交媒体平台

  • 用户帖子包含 文本、图片、视频、点赞、评论 等,格式复杂且变化快,MongoDB 更适合。

MySQL 适用场景

高事务要求(如银行、支付系统)
数据结构固定(如企业 ERP、CRM 系统)
复杂查询与报表分析(多表 JOIN)

示例:银行系统

  • 账户交易需要 强一致性事务支持,MySQL 更适合。

总结

MongoDBMySQL
适合场景大数据、动态数据、实时分析事务、数据完整性要求高
示例社交平台、日志存储银行、ERP、CRM

最终总结

维度MongoDBMySQL
数据存储JSON 文档(BSON)表(行 + 列)
查询语言Mongo 查询语法(基于 JavaScript)SQL
事务支持4.0+ 支持事务,但不如 SQL 强支持 ACID 事务
扩展性水平扩展(Sharding)垂直扩展(升级服务器)
适合场景大数据、内容管理、社交平台事务处理、金融系统

选择建议

  • 如果是 高并发、大数据、非结构化存储,✅ MongoDB 更合适
  • 如果是 事务、数据一致性要求高,✅ MySQL 更合适

1. 什么是字符集?

字符集(Character Set)决定了 数据库如何存储、读取和表示字符。如果字符集选择不当,可能会导致:

  • 存储占用不合理(存储空间变大或变小)。
  • 数据查询性能下降(字符编码转换耗时)。
  • 数据乱码(字符存储和解析方式不一致)。

2. 常见 MySQL 字符集

字符集每个字符最大占用字节特点
GBK2适合中文,存储空间比 UTF-8 少,但不支持特殊符号和国际化。
UTF-83国际通用字符集,支持多语言,适合中英文混合。
latin11MySQL 早期默认字符集,仅支持英文
utf8mb44完全兼容 UTF-8,支持 Emoji 表情和特殊符号。

3. 字符集选择规则

外贸、国际业务(多语言)utf8mb4(保证兼容性)
国内中文网站GBK(存储效率高)
纯英文数据latin1(存储空间最小,性能好)


4. 影响示例

(1)字符存储占用

存储 "你好"

  • GBK2 × 2 = 4 字节
  • UTF-83 × 2 = 6 字节
  • utf8mb44 × 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 中,字符集可以在 不同层级 进行设置,分别是:

  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 配置文件):

[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,  -- 该列为 GBK
    email 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(主键)商品名称订单日期
1001A1苹果2024-03-01
1001A2香蕉2024-03-01

❌ 问题:

  • 商品名称 只依赖于 商品ID,但和 订单ID 没关系,属于 “部分依赖”
  • 如果同一个商品出现在多个订单中,商品名称就会重复,导致冗余!

✅ 解决办法:
拆分为两张表:

  1. 订单表(去掉商品名称,只存 订单ID订单日期
  2. 商品表(存 商品ID商品名称
  3. 订单-商品关联表(订单ID + 商品ID 作为联合主键)
订单ID(主键)订单日期
10012024-03-01
商品ID(主键)商品名称
A1苹果
A2香蕉
订单ID商品ID
1001A1
1001A2

✅ 这样,商品信息只存一份,避免冗余!


第三范式(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,就无法撤销。

📌 举例:

-- 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. 其他区别

特点InnoDBMyISAM
事务支持不支持
外键支持不支持
锁机制行锁表锁
MVCC支持不支持
索引存储聚簇索引非聚簇索引
全文索引MySQL 5.6+ 支持支持
崩溃恢复支持不支持
数据存储不保存行数保存行数
读写场景读写均衡读多写少

总结

  • InnoDB 适合 高并发、事务场景(如订单、支付)。
  • MyISAM 适合 查询多、写入少的场景(如日志、统计)。
  • 实际应用中,一般推荐使用 InnoDB,除非有特殊需求(如超大规模的只读数据)。

https://github.com/0voice


http://www.kler.cn/a/573088.html

相关文章:

  • 优化cache利用、减少cache miss的方法
  • LLM 模型 Prompt 工程
  • [Computer Vision]图像分割技术
  • Android10.0关于发送广播Sending non-protected broadcast android.price.public.close
  • JVM(Java Virtual Machine,Java 虚拟机)的作用
  • 机器分类的基石:逻辑回归Logistic Regression
  • JavaWeb-HttpServlet源码分析
  • SpringBoot为什么要禁止循环依赖?
  • 网络安全公钥密码体制
  • 不懂ui->layout()->removeWidget(bar);
  • 2W8000字 LLM架构文章阅读指北
  • 题目梳理2025[长期更新]
  • 在阿里云ECS云服务器上安装、配置及高效使用Docker与Docker Compose
  • 数字北极星与DeepSeek深度融合,引领流程智能的AI革命
  • 第十二届蓝桥杯大学A组java省赛答案整理
  • 【简单的C++围棋游戏开发示例】
  • react 编写一个待办事项,函数优化,组件传值
  • Go 语言中常用的爬虫框架和工具库
  • 【不是广告】华为昇腾的一小步,Pytorch的一大步
  • 权限管理Vue实现