专栏文章
专栏文章
MySQL 系列
1. MySQL 系列 #01:MySQL 简介 2. MySQL 系列 #02:MySQL 数据类型与 Java 类型映射 3. MySQL 系列 #03:MySQL 基础架构与执行流程 4. MySQL 系列 #04:MySQL InnoDB 日志系统 5. MySQL 系列 #05:MySQL 事务与 MVCC 6. MySQL 系列 #06:MySQL 索引原理与优化 7. MySQL 系列 #07:MySQL 锁机制 8. MySQL 系列 #08:MySQL 性能问题排查 9. MySQL 系列 #09:MySQL 主备复制与高可用 10. MySQL 系列 #10:MySQL 实战技巧与常见陷阱 11. MySQL 系列 #11:MySQL 数据库设计规范 12. MySQL 系列 #12:MySQL SQL 函数与查询技巧 13. MySQL 系列 #13:MySQL InnoDB Buffer Pool 原理 14. MySQL 系列 #14:MySQL 排序与聚合原理

MySQL 系列 #01:MySQL 简介

发布于 2026-05-26 10:32 👁 13 次阅读
#mysql#数据库#sql

MySQL 是世界上最流行的开源关系型数据库,由 Oracle 维护。以高性能、高可靠、易部署著称,是 Web 应用的首选数据库。 InnoDB 存储引擎(默认)支持事务、外键、行级锁,是生产环境的标准选择。

⚠️ 版本说明:本文以 MySQL 8.0 为基准。8.0 相比 5.7 引入了窗口函数、CTE、降序索引、JSON 增强等重要特性。

📎 关联文档MySQL数据类型×Java类型映射 — 字段类型选型与 Java 映射详细说明。


目录

章节 说明
核心架构 逻辑架构、InnoDB 存储引擎、Buffer Pool
安装与配置 安装、my.cnf 常用配置、连接
存储引擎 InnoDB vs MyISAM、引擎选择
索引 B+ 树原理、索引类型、覆盖索引、索引失效
事务与锁 ACID、隔离级别、行锁/表锁、MVCC、死锁
SQL 优化 EXPLAIN 解读、慢查询、常见优化手段
主从复制 Binlog、复制原理、读写分离
备份与恢复 mysqldump、物理备份、Binlog 恢复
快速参考卡 常用命令、数据类型速查、配置速查

核心架构

mysql arch

InnoDB 核心组件

组件 说明
Buffer Pool 内存缓冲池,缓存数据页和索引页,最重要的性能参数
Redo Log 崩溃恢复日志(WAL),保证事务持久性,循环写入
Undo Log 事务回滚日志,MVCC 多版本并发控制的基础
Change Buffer 缓存对非唯一二级索引的写操作,延迟合并
Doublewrite Buffer 防止页面部分写入导致的数据损坏

三大日志

日志 层级 作用
Binlog Server 层 主从复制、数据恢复(逻辑日志)
Redo Log InnoDB 层 崩溃恢复(物理日志,循环写)
Undo Log InnoDB 层 事务回滚、MVCC 读旧版本数据

安装与配置

安装

# macOS
brew install mysql@8.0
brew services start mysql@8.0

# 安全初始化(设置 root 密码)
mysql_secure_installation

# 验证
mysql -u root -p
mysql> SELECT VERSION();

常用 my.cnf 配置

[mysqld]
# 基础
port            = 3306
character-set-server = utf8mb4
collation-server     = utf8mb4_unicode_ci

# InnoDB
innodb_buffer_pool_size = 1G          # 建议设为物理内存的 50%~75%
innodb_buffer_pool_instances = 4      # buffer pool 实例数,建议 CPU 核数
innodb_flush_log_at_trx_commit = 1    # 1=最安全(每次提交刷盘), 2=性能好但崩溃可能丢1秒数据
innodb_file_per_table = ON            # 每张表独立 ibd 文件
innodb_log_file_size = 256M           # Redo Log 单文件大小

# 连接
max_connections = 500
wait_timeout    = 600
interactive_timeout = 600

# 慢查询
slow_query_log  = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1                   # 超过 1 秒记录慢查询
log_queries_not_using_indexes = ON    # 未命中索引的查询也记录

# Binlog(主从复制必需)
server-id   = 1
log-bin     = mysql-bin
binlog_format = ROW
expire_logs_days = 7

常用连接与管理命令

# 连接
mysql -h 127.0.0.1 -P 3306 -u root -p
mysql -u root -p mydb < dump.sql     # 导入 SQL 文件

# 查看状态
SHOW STATUS LIKE 'Threads_connected';  -- 当前连接数
SHOW STATUS LIKE 'Innodb_buffer_pool%'; -- Buffer Pool 命中率
SHOW PROCESSLIST;                       -- 查看当前连接和执行的 SQL
SHOW ENGINE INNODB STATUS\G            -- InnoDB 详细状态

# 数据库操作
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
DROP DATABASE mydb;
USE mydb;
SHOW DATABASES;
SHOW TABLES;
DESCRIBE users;          -- 查看表结构
SHOW CREATE TABLE users; -- 查看建表语句

存储引擎

InnoDB vs MyISAM

特性 InnoDB MyISAM
事务 ✅ 支持 ❌ 不支持
外键 ✅ 支持 ❌ 不支持
锁粒度 行锁(+ 表锁) 表锁
崩溃恢复 ✅ 自动(Redo Log) ❌ 需修复
全文索引 ✅ 5.6+ 支持 ✅ 支持
读性能 略低 略高(无事务开销)
写性能 高(行锁并发) 低(表锁串行)
适用场景 所有生产场景 只读/归档(已基本淘汰)

结论:新建表一律使用 InnoDB,MyISAM 已无使用场景。


索引

B+ 树原理

InnoDB 使用 B+ 树作为索引结构:
- 所有数据存储在叶节点(Leaf Node)
- 叶节点通过双向链表连接,支持范围查询
- 非叶节点只存索引键,不存数据
- 树高通常为 3~4 层,千万级数据 3 次 IO 即可定位

主键索引(聚簇索引):叶节点存完整行数据
二级索引(非聚簇):叶节点存主键值,查完整行需"回表"

索引类型

-- 主键索引(自动创建)
PRIMARY KEY (id)

-- 唯一索引
CREATE UNIQUE INDEX uq_email ON users (email);

-- 普通索引
CREATE INDEX idx_status ON users (status);

-- 复合索引(遵循最左前缀原则)
CREATE INDEX idx_user_status_time ON orders (user_id, status, created_at);

-- 前缀索引(长字符串节省空间)
CREATE INDEX idx_email_prefix ON users (email(20));

-- 全文索引(5.6+ InnoDB 支持,中文需配合 ngram 解析器)
CREATE FULLTEXT INDEX ft_content ON articles (title, content) WITH PARSER ngram;

覆盖索引

-- 查询字段全部在索引中,无需回表(EXPLAIN 中 Extra 显示 Using index)
-- 复合索引 (user_id, status, amount)
SELECT user_id, status, amount
FROM orders
WHERE user_id = 1 AND status = 'paid';
-- ↑ 三列均在索引中,不需要回表

索引失效场景

-- 1. 对索引列使用函数或运算
WHERE YEAR(created_at) = 2024          -- ❌ 失效
WHERE created_at >= '2024-01-01'       -- ✅ 有效

-- 2. 隐式类型转换(字符串列传入数字)
WHERE phone = 13800138000              -- ❌ phone 是 VARCHAR,传入数字会失效
WHERE phone = '13800138000'            -- ✅ 有效

-- 3. LIKE 前缀通配符
WHERE name LIKE '%张%'                 -- ❌ 失效
WHERE name LIKE '张%'                  -- ✅ 有效

-- 4. 违反最左前缀原则
-- 复合索引 (a, b, c)
WHERE b = 1 AND c = 2                  -- ❌ 跳过 a,失效
WHERE a = 1 AND c = 2                  -- ⚠️ 只用到 a 列
WHERE a = 1 AND b = 2                  -- ✅ 命中 a, b

-- 5. OR 条件中有非索引列
WHERE age = 25 OR name = '张三'        -- ❌ name 无索引则整体失效

-- 6. NOT IN / NOT EXISTS(通常不走索引)
WHERE status NOT IN (0, 2)             -- ❌ 一般失效

事务与锁

隔离级别

隔离级别 脏读 不可重复读 幻读 MySQL 默认
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ ⚠️ 部分
SERIALIZABLE

MySQL InnoDB 在 REPEATABLE READ 下通过 Next-Key Lock 解决了大部分幻读问题。

-- 查看和设置隔离级别
SELECT @@transaction_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 事务操作
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
-- 或 ROLLBACK;

锁类型

粒度 说明
表锁(Table Lock) 开销小,并发低;DDL 操作时自动加
行锁(Row Lock) InnoDB 默认,并发高
记录锁(Record Lock) 锁定索引记录
间隙锁(Gap Lock) 索引间隙 防止幻读,锁定不存在的范围
Next-Key Lock 行 + 间隙 记录锁 + 间隙锁,InnoDB 默认
意向锁(IS/IX) 行锁与表锁协调的标志锁
-- 手动加锁
SELECT * FROM orders WHERE id = 1 FOR UPDATE;      -- 排他锁(写锁)
SELECT * FROM orders WHERE id = 1 LOCK IN SHARE MODE; -- 共享锁(读锁)

-- 查看锁等待
SELECT * FROM performance_schema.data_lock_waits\G
-- 或
SHOW ENGINE INNODB STATUS\G   -- 查看 TRANSACTIONS 段

MVCC(多版本并发控制)

每行数据有两个隐藏字段:
  DB_TRX_ID:最近修改该行的事务 ID
  DB_ROLL_PTR:指向 Undo Log 的指针

读操作(快照读):根据事务开始时的 ReadView,
  通过 Undo Log 链找到对应版本,不加锁,高并发

写操作(当前读):SELECT...FOR UPDATE、UPDATE、DELETE
  读取最新版本,加锁

死锁处理

-- 查看最近一次死锁信息
SHOW ENGINE INNODB STATUS\G   -- 查看 LATEST DETECTED DEADLOCK 段

-- 死锁预防原则:
-- 1. 固定加锁顺序(所有事务按相同顺序访问表/行)
-- 2. 缩短事务,减少持锁时间
-- 3. 大事务拆小事务
-- 4. 避免在事务中与用户交互

SQL 优化

EXPLAIN 解读

EXPLAIN SELECT * FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'paid' AND u.age > 25;
字段 说明 好的值
type 访问类型 const > eq_ref > ref > range > index > ALL
key 实际使用的索引 非 NULL
key_len 索引使用长度 越小越好(在命中前提下)
rows 预估扫描行数 越小越好
filtered 过滤后行数占比 越大越好
Extra 附加信息 避免 Using filesortUsing temporary
-- 开启 Optimizer Trace(查看优化器决策过程)
SET optimizer_trace = 'enabled=on';
SELECT * FROM orders WHERE user_id = 1;
SELECT * FROM information_schema.OPTIMIZER_TRACE\G
SET optimizer_trace = 'enabled=off';

慢查询分析

# 查看慢查询日志
tail -f /var/log/mysql/slow.log

# 用 mysqldumpslow 汇总分析
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log  # 按时间排序,取 top 10
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log  # 按次数排序

常见优化手段

-- 1. 分页优化:大偏移量用子查询 + 主键
-- 慢(扫描 10020 行)
SELECT * FROM orders ORDER BY id LIMIT 10000, 20;
-- 快(先定位主键,再取数据)
SELECT * FROM orders WHERE id >= (
    SELECT id FROM orders ORDER BY id LIMIT 10000, 1
) ORDER BY id LIMIT 20;

-- 2. 避免 SELECT *,只查需要的列
SELECT id, status, amount FROM orders WHERE user_id = 1;

-- 3. 用 EXISTS 替代 IN(子查询返回大量数据时)
SELECT * FROM users u WHERE EXISTS (
    SELECT 1 FROM orders o WHERE o.user_id = u.id
);

-- 4. 批量写入替代逐条插入
INSERT INTO logs (user_id, action, created_at) VALUES
    (1, 'login', NOW()),
    (2, 'purchase', NOW()),
    (3, 'logout', NOW());

-- 5. 强制使用/忽略索引(调试用)
SELECT * FROM orders USE INDEX (idx_user_id) WHERE user_id = 1;
SELECT * FROM orders IGNORE INDEX (idx_status) WHERE status = 'paid';

主从复制

复制原理

主库(Master)                副库(Slave)
    ↓ 写操作
Binlog(ROW 格式)  →→→→→→  IO Thread 读取 Binlog
                              ↓
                           Relay Log(中继日志)
                              ↓
                           SQL Thread 回放
                              ↓
                           从库数据同步
-- 主库:查看 Binlog 状态
SHOW MASTER STATUS;
SHOW BINARY LOGS;
SHOW BINLOG EVENTS IN 'mysql-bin.000001' LIMIT 10;

-- 从库:查看复制状态
SHOW SLAVE STATUS\G
-- 关注:
--   Slave_IO_Running: Yes
--   Slave_SQL_Running: Yes
--   Seconds_Behind_Master: 0  (复制延迟秒数)

读写分离注意事项

写操作 → 主库
读操作 → 从库(注意主从延迟!)

主从延迟场景下读从库可能读到旧数据,解决方案:
1. 强一致性读(如余额)→ 强制走主库
2. 等待从库追上(Semi-sync 半同步复制)
3. 业务层容忍短暂延迟

备份与恢复

# mysqldump 逻辑备份(适合中小型数据库)
mysqldump -u root -p \
  --single-transaction \     # InnoDB 一致性快照,不锁表
  --master-data=2 \          # 记录 Binlog 位点(用于增量恢复)
  --routines --triggers \    # 包含存储过程和触发器
  mydb > mydb_backup.sql

# 恢复
mysql -u root -p mydb < mydb_backup.sql

# 备份所有数据库
mysqldump -u root -p --all-databases --single-transaction > all_backup.sql

# 使用 Binlog 做增量恢复(从某个位点开始)
mysqlbinlog --start-position=154 \
  --stop-datetime="2024-01-15 12:00:00" \
  mysql-bin.000001 | mysql -u root -p

# xtrabackup 物理热备(大型数据库推荐,速度快)
xtrabackup --backup --target-dir=/backup/full
xtrabackup --prepare --target-dir=/backup/full
xtrabackup --copy-back --target-dir=/backup/full

快速参考卡

常用管理命令

命令 说明
SHOW PROCESSLIST 查看当前连接和 SQL
KILL {id} 终止指定连接
SHOW ENGINE INNODB STATUS\G InnoDB 详细状态
SHOW INDEX FROM {table} 查看表索引
ANALYZE TABLE {table} 更新统计信息
OPTIMIZE TABLE {table} 整理碎片(慎用,会锁表)
SHOW VARIABLES LIKE '%buffer%' 查看 Buffer Pool 配置
SHOW STATUS LIKE 'Innodb_buffer_pool_read%' Buffer Pool 命中率

Buffer Pool 命中率计算

SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
-- Innodb_buffer_pool_reads:从磁盘读取的次数
-- Innodb_buffer_pool_read_requests:总读取请求次数
-- 命中率 = 1 - reads / read_requests,正常应 > 99%

数据类型速查(简版)

场景 推荐类型 Java 类型
主键 ID BIGINT UNSIGNED AUTO_INCREMENT Long
状态/枚举 TINYINT Integer
金额/价格 DECIMAL(19,4) BigDecimal
普通字符串 VARCHAR(128) String
长文本 TEXT String
时间戳 DATETIME LocalDateTime
布尔 TINYINT + tinyint1isBit=false Integer
JSON JSON (5.7.8+) String + 自定义 TypeHandler

详细类型映射见 MySQL数据类型×Java类型映射


参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。

发表评论