MySQL 是一款开源的关系型数据库管理系统(RDBMS),由瑞典 MySQL AB 公司开发,现属于 Oracle 旗下。它使用 SQL(Structured Query Language) 作为操作语言,支持多线程、多用户,能够处理大量数据。
1.2 MySQL 的整体架构
MySQL 采用插件式存储引擎架构,这种设计让它在灵活性上表现出色。我们可以通过一张架构图来理解 MySQL 的工作层次:
flowchart TD
subgraph 应用层["📱 应用层"]
A["连接器 Connection Pool"]
B["SQL 接口 SQL Interface"]
C["解析器 Parser"]
D["优化器 Optimizer"]
E["缓存与缓冲 Cache & Buffer"]
end
subgraph 引擎层["⚙️ 存储引擎层(插件式)"]
F["InnoDB(默认)"]
G["MyISAM"]
H["Memory"]
I["Archive"]
end
subgraph 物理层["💾 物理存储层"]
J["数据文件 Data Files"]
K["索引文件 Index Files"]
L["日志文件 Log Files"]
end
A --> B --> C --> D --> E
D --> F
D --> G
D --> H
D --> I
F --> J
G --> J
H --> J
I --> J
F --> K
G --> K
F --> L
style A fill:#e3f2fd
style F fill:#c8e6c9
style J fill:#fff3e0
1.3 核心存储引擎对比
MySQL 支持多种存储引擎,不同引擎在功能特性上差异明显:
特性
InnoDB
MyISAM
Memory
事务支持
✅ 支持
❌ 不支持
❌ 不支持
行级锁
✅ 支持
❌ 表级锁
❌ 表级锁
外键约束
✅ 支持
❌ 不支持
❌ 不支持
崩溃恢复
✅ 支持
❌ 不支持
❌ 不支持
全文索引
✅ 支持(5.6+)
✅ 支持
❌ 不支持
存储限制
64TB
256TB
受 RAM 限制
适用场景
事务业务、高并发
只读/静态表
临时表、缓存
💡 推荐:日常业务开发首选 InnoDB,它是 MySQL 5.5 之后的默认引擎,支持事务和行锁,功能全面。
1.4 连接 MySQL 的几种方式
1 2 3 4 5 6 7 8 9 10
# 方式一:命令行客户端连接 mysql -u root -p
# 方式二:指定主机和端口 mysql -h 192.168.1.100 -P 3306 -u root -p
# 方式三:连接后选择数据库 mysql -u root -p USE my_database; SHOW TABLES;
1 2 3 4
-- 查看 MySQL 版本和状态 SELECT VERSION(); SHOW STATUS; SHOW VARIABLES LIKE'version%';
-- 修改表:添加索引 ALTER TABLE users ADD INDEX idx_phone (phone);
-- 修改表:重命名表 ALTER TABLE users RENAME TO user_info;
-- 删除表(谨慎操作!) DROPTABLE IF EXISTS users;
3.3 约束详解
约束是用来限制字段取值合法性的规则,是保证数据完整性的重要手段:
flowchart LR
A["数据完整性约束"] --> B["主键约束\nPrimary Key"]
A --> C["唯一约束\nUnique Key"]
A --> D["非空约束\nNot Null"]
A --> E["检查约束\nCheck"]
A --> F["外键约束\nForeign Key"]
A --> G["默认值约束\nDefault"]
B --> B1["唯一标识\n自动索引"]
C --> C1["字段值不可重复"]
D --> D1["字段必须有值"]
E --> E1["字段值满足条件"]
F --> F1["表间关联关系"]
G --> G1["未填时自动填入"]
style B fill:#c8e6c9
style C fill:#c8e6c9
style D fill:#e3f2fd
style E fill:#fff3e0
style F fill:#f8bbd0
style G fill:#f3e5f5
-- 条件查询 SELECT username, email FROM users WHERE status =1AND id >10;
-- 排序查询 SELECT*FROM users ORDERBY created_at DESC, id ASC;
-- 分页查询(重要!) SELECT*FROM users ORDERBY id LIMIT 10OFFSET0; -- 第一页,每页10条 SELECT*FROM users ORDERBY id LIMIT 10OFFSET10; -- 第二页
-- 简化写法:LIMIT start, count SELECT*FROM users ORDERBY id LIMIT 0, 10; SELECT*FROM users ORDERBY id LIMIT 10, 10;
-- 聚合查询 SELECT COUNT(*) AS total_users, COUNT(DISTINCT status) AS status_types, MAX(created_at) AS latest_registration, MIN(created_at) AS earliest_registration, AVG(id) AS avg_id FROM users;
-- 分组查询 + 聚合函数 SELECT status, COUNT(*) AS user_count, MAX(created_at) AS last_time FROM users GROUPBY status HAVING user_count >5; -- HAVING 对分组后的结果进行过滤
-- 子查询 SELECT*FROM users WHERE id IN (SELECT user_id FROM orders WHERE total_amount >1000);
-- 关联查询:多表联合 SELECT u.username, o.order_no, o.total_amount FROM users u INNERJOIN orders o ON u.id = o.user_id WHERE o.status ='paid' ORDERBY o.created_at DESC;
-- 更新单个字段 UPDATE users SET phone ='13900139000'WHERE id =1;
-- 更新多个字段 UPDATE users SET email ='new_email@example.com', status =0, updated_at = NOW() WHERE id =1;
-- 批量更新(谨慎使用,最好加条件) UPDATE users SET status =1WHERE created_at >'2026-01-01';
-- 使用 CASE 进行条件更新 UPDATE orders SET status =CASE WHEN status ='pending'AND pay_time < DATE_SUB(NOW(), INTERVAL1HOUR) THEN'cancelled' WHEN status ='shipped'AND delivery_time < DATE_SUB(NOW(), INTERVAL7DAY) THEN'completed' ELSE status END WHERE status IN ('pending', 'shipped');
flowchart TD
A["表 A(订单表)"] --> B[" INNER JOIN\n 内连接"]
A --> C[" LEFT JOIN\n 左连接"]
A --> D[" RIGHT JOIN\n 右连接"]
A --> E[" FULL JOIN\n 全连接"]
F["表 B(用户表)"] --> B
F --> C
F --> D
F --> E
B --> G["返回 A∩B\n交集部分"]
C --> H["返回 A∪A∩B\nA的全部+B的匹配"]
D --> I["返回 A∩B∪B\nB的全部+A的匹配"]
E --> J["返回 A∪B\n并集全部"]
style G fill:#c8e6c9
style H fill:#e3f2fd
style I fill:#fff3e0
style J fill:#f8bbd0
-- INNER JOIN:只返回两边匹配到的记录 SELECT u.username, o.order_no, o.total_amount FROM users u INNERJOIN orders o ON u.id = o.user_id WHERE o.status ='paid';
-- LEFT JOIN:返回左表所有记录,右表没有匹配的显示 NULL SELECT u.username, COUNT(o.id) AS order_count, COALESCE(SUM(o.total_amount), 0) AS total_spent FROM users u LEFTJOIN orders o ON u.id = o.user_id GROUPBY u.id, u.username ORDERBY total_spent DESC;
-- 多表关联查询 SELECT u.username, o.order_no, oi.product_name, oi.quantity, oi.price FROM users u INNERJOIN orders o ON u.id = o.user_id INNERJOIN order_items oi ON o.id = oi.order_id WHERE o.status ='paid'AND oi.quantity >2 ORDERBY o.created_at DESC;
五、索引:数据库的性能之钥
5.1 索引的概念与原理
索引是 MySQL 中用于加速数据检索的数据结构,可以类比为书籍的目录。创建合适的索引能让查询从”遍历全表”变成”直接定位”。
flowchart LR
A["📖 全表扫描"] --> B["🤷 无索引"]
C["⚡ 索引查询"] --> D["📑 B+Tree 索引"]
B --> B1["逐行扫描 1000 行\n耗时:1000ms"]
D --> D1["二分查找 10 步\n耗时:10ms"]
style A fill:#ffcdd2
style C fill:#c8e6c9
style B1 fill:#ffcdd2
style D1 fill:#c8e6c9
-- 创建表时直接添加索引 CREATE TABLE products ( id BIGINTPRIMARY KEY AUTO_INCREMENT, category_id BIGINTNOT NULL, name VARCHAR(100) NOT NULL, price DECIMAL(10, 2), description TEXT, created_at DATETIME, -- 普通索引 INDEX idx_category (category_id), INDEX idx_created (created_at), -- 组合索引(遵循最左前缀原则) INDEX idx_cat_price (category_id, price), -- 全文索引 FULLTEXT INDEX ft_name_desc (name, description) ) ENGINE=InnoDB;
-- 已存在表添加索引 CREATE INDEX idx_name ON products(name); CREATE INDEX idx_cat_price ON products(category_id, price); CREATE FULLTEXT INDEX ft_desc ON products(description);
-- 查看表的索引 SHOW INDEX FROM products;
-- 删除索引 DROP INDEX idx_name ON products; DROP INDEX idx_created ON products;
5.4 最左前缀原则(组合索引核心)
组合索引 (a, b, c) 的查询效率如下:
flowchart TD
A["组合索引 (a, b, c)"] --> B["✅ 可以使用索引"]
A --> C["❌ 无法使用索引"]
B --> B1["WHERE a = ?"]
B --> B2["WHERE a = ? AND b = ?"]
B --> B3["WHERE a = ? AND b = ? AND c = ?"]
B --> B4["WHERE a IN (?, ?) AND b = ?"]
B --> B5["WHERE a = ? AND b > ?"]
C --> C1["WHERE b = ?"]
C --> C2["WHERE c = ?"]
C --> C3["WHERE b = ? AND c = ?"]
style B fill:#c8e6c9
style B1 fill:#c8e6c9
style B2 fill:#c8e6c9
style B3 fill:#c8e6c9
style B4 fill:#c8e6c9
style B5 fill:#c8e6c9
style C fill:#ffcdd2
style C1 fill:#ffcdd2
style C2 fill:#ffcdd2
style C3 fill:#ffcdd2
1 2 3 4 5 6 7 8 9 10 11
-- 创建组合索引 CREATE INDEX idx_status_created ON orders(status, created_at);
-- 这些查询能用到索引(最左前缀原则) EXPLAIN SELECT*FROM orders WHERE status ='pending'; EXPLAIN SELECT*FROM orders WHERE status ='pending'AND created_at >'2026-01-01'; EXPLAIN SELECT*FROM orders WHERE status ='paid'AND created_at BETWEEN'2026-01-01'AND'2026-06-01';
-- 这些查询无法用到索引 EXPLAIN SELECT*FROM orders WHERE created_at >'2026-01-01'; -- 跳过最左列 EXPLAIN SELECT*FROM orders WHERE status ='pending'AND created_at >'2026-01-01'AND status ='paid'; -- 顺序颠倒
-- 从 A 账户扣款 UPDATE accounts SET balance = balance -1000WHERE user_id =1AND balance >=1000;
-- 给 B 账户充值 UPDATE accounts SET balance = balance +1000WHERE user_id =2;
-- 判断操作是否成功,决定提交或回滚 -- 如果 A 余额不足,第一条 UPDATE 影响行数为 0,此时应该回滚 IF (@@row_count=0) THEN ROLLBACK; ELSE COMMIT; END IF;
6.4 并发事务带来的问题
flowchart TD
A["并发问题"] --> B["脏读\nDirty Read"]
A --> C["不可重复读\nNon-repeatable Read"]
A --> D["幻读\nPhantom Read"]
B --> B1["读取了其他事务\n未提交的数据"]
C --> C1["同一事务中两次读取\n同一数据结果不同"]
D --> D1["同一事务中两次查询\n结果集不一致\n(多了或少了行)"]
style A fill:#e3f2fd
style B fill:#ffcdd2
style C fill:#fff3e0
style D fill:#f8bbd0
-- 查看更详细的信息 EXPLAIN EXTENDED SELECT ...; SHOW WARNINGS; -- 查看优化后的查询语句
7.2 EXPLAIN 输出字段解读
1 2 3 4 5 6
EXPLAIN SELECT u.username, o.order_no FROM users u INNERJOIN orders o ON u.id = o.user_id WHERE u.status =1 ORDERBY o.created_at DESC LIMIT 10;
字段
含义
优化目标值
id
查询执行的顺序,id 越大越先执行
-
select_type
查询类型(SIMPLE/PRIMARY/SUBQUERY/UNION 等)
越简单越好
table
涉及的表
-
type
访问类型,关键指标
system > const > eq_ref > ref > range > index > ALL
possible_keys
可能用到的索引
-
key
实际使用的索引
不为 NULL 表示用到索引
key_len
索引长度
越短越好
rows
预计扫描的行数
越少越好
Extra
附加信息(Using filesort/Using index 等)
避免 Using filesort
7.3 访问类型等级
flowchart TD
A["type 访问类型"] --> B["system\n(系统表,唯一一行)"]
A --> C["const\n(主键/唯一索引等值查询)"]
A --> D["eq_ref\n(唯一索引连接)"]
A --> E["ref\n(普通索引等值查询)"]
A --> F["range\n(索引范围查询)"]
A --> G["index\n(全文索引扫描)"]
A --> H["ALL\n(全表扫描,最差)"]
B --> B1["1 行"]
C --> C1["1 行"]
D --> D1["1 行/连接"]
E --> E1["多行"]
F --> F1["符合范围的多行"]
G --> G1["全索引"]
H --> H1["全表数据"]
B -.- B2["✨ 最优"]:::good
C -.- C2["✨ 优"]:::good
D -.- D2["✅ 良"]:::ok
E -.- E2["✅ 良"]:::ok
F -.- F2["⚠️ 一般"]:::warn
G -.- G2["⚠️ 差"]:::warn
H -.- H2["❌ 差"]:::bad
classDef good fill:#c8e6c9
classDef ok fill:#e3f2fd
classDef warn fill:#fff3e0
classDef bad fill:#ffcdd2
-- 1. 避免 SELECT *,只查询需要的字段 -- ❌ 低效 SELECT*FROM orders WHERE id =1; -- ✅ 高效 SELECT id, order_no, total_amount FROM orders WHERE id =1;
-- 2. 使用 LIMIT 限制返回行数 -- ❌ 低效 SELECT*FROM orders WHERE status ='paid'; -- ✅ 高效 SELECT*FROM orders WHERE status ='paid'ORDERBY created_at DESC LIMIT 100;
-- 3. 使用覆盖索引(Extra: Using index) -- ❌ 低效(回表查询) SELECT email, phone FROM users WHERE id =1; -- ✅ 高效(索引包含所有字段,无需回表) CREATE INDEX idx_id_phone_email ON users(id, phone, email); SELECT phone, email FROM users WHERE id =1;
-- 4. 避免前置通配符(导致索引失效) -- ❌ 低效(无法使用索引) SELECT*FROM users WHERE phone LIKE'%138%'; -- ✅ 高效(可以使用索引) SELECT*FROM users WHERE phone LIKE'138%';
-- 5. 使用延迟关联优化大表分页 -- ❌ 低效(深度分页,OFFSET 大时性能差) SELECT*FROM orders ORDERBY id LIMIT 1000000, 10; -- ✅ 高效(延迟关联,先定位 ID 再关联) SELECT o.*FROM orders o INNERJOIN ( SELECT id FROM orders ORDERBY id LIMIT 1000000, 10 ) AS t ON o.id = t.id;
flowchart LR
A["MySQL 备份方式"] --> B["物理备份\n冷备份"]
A --> C["逻辑备份\nmysqldump"]
A --> D["增量备份\nbinlog"]
B --> B1["直接复制\n数据文件"]
C --> C1["导出 SQL\n脚本"]
D --> D1["记录变化\n增量恢复"]
style A fill:#e3f2fd
style B fill:#c8e6c9
style C fill:#fff3e0
style D fill:#f8bbd0
flowchart LR
A["入门阶段"] --> B["基础阶段"]
B --> C["进阶阶段"]
C --> D["精通阶段"]
A --> A1["安装配置"]
A --> A2["SQL 基础"]
A --> A3["CRUD 操作"]
B --> B1["索引原理"]
B --> B2["事务概念"]
B --> B3["关联查询"]
C --> C1["查询优化"]
C --> C2["锁机制"]
C --> C3["主从复制"]
D --> D1["性能调优"]
D --> D2["集群架构"]
D --> D3["源码阅读"]
style A fill:#e3f2fd
style B fill:#c8e6c9
style C fill:#fff3e0
style D fill:#f8bbd0