← 返回
课程

MySQL 快速复习版

首发 2026/05/05 阅读 2 评论 0 更新 2026/05/05

MySQL 快速复习版

用途:考前速看、面试前回顾、写 SQL 前查模板。
风格:只保留高频概念、常用语法、易错点和面试表达。
范围:MySQL 基础篇、进阶篇、运维篇。


0. 总复习路线

MySQL 可以按三层记:

text
基础层:库、表、字段、增删改查、多表查询、事务
原理层:存储引擎、索引、执行计划、锁、InnoDB、MVCC
运维层:日志、主从复制、分库分表、MyCat、读写分离

最重要的一条主线:

rust
SQL 怎么写 -> SQL 怎么查得快 -> 并发下怎么保证正确 -> 数据量大后怎么扩展

第一部分:基础 SQL 必会


1. 数据库基本概念

名称 含义 记忆
DB 数据库,存储数据的仓库 仓库
DBMS 数据库管理系统,如 MySQL 管仓库的软件
SQL 操作关系型数据库的语言 操作命令

关系型数据库特点:

sql
数据存储在二维表中。
表和表之间可以通过字段建立关系。
SQL 是操作关系型数据库的统一标准。

MySQL 常用默认信息:

css
默认端口:3306
超级用户:root
本地连接:mysql -u root -p
远程连接:mysql -h 主机IP -P 3306 -u 用户名 -p

易错点:

css
-P 大写:端口
-p 小写:密码
SQL 语句通常以 ; 结尾

2. SQL 分类

分类 作用 关键字
DDL 定义库、表、字段 CREATEALTERDROP
DML 增删改表中数据 INSERTUPDATEDELETE
DQL 查询数据 SELECT
DCL 用户和权限控制 CREATE USERGRANTREVOKE

口诀:

text
DDL 建结构,DML 改数据,DQL 查数据,DCL 管权限。

SQL 注释:

sql
-- 单行注释
# 单行注释
/* 多行注释 */

3. DDL:库和表结构

3.1 数据库操作

sql
SHOW DATABASES;
SELECT DATABASE();
CREATE DATABASE 数据库名;
CREATE DATABASE IF NOT EXISTS 数据库名 DEFAULT CHARSET utf8mb4;
USE 数据库名;
DROP DATABASE IF EXISTS 数据库名;

常用推荐:

sql
CREATE DATABASE IF NOT EXISTS db01 DEFAULT CHARSET utf8mb4;

3.2 表操作

查看表:

sql
SHOW TABLES;
DESC 表名;
SHOW CREATE TABLE 表名;

创建表模板:

sql
CREATE TABLE 表名 (
    字段名 字段类型 [约束] [COMMENT '注释'],
    字段名 字段类型 [约束] [COMMENT '注释']
) COMMENT '表注释';

示例:

sql
CREATE TABLE emp (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID',
    name VARCHAR(50) NOT NULL COMMENT '姓名',
    age INT COMMENT '年龄',
    entrydate DATE COMMENT '入职日期'
) COMMENT '员工表';

删除表:

sql
DROP TABLE IF EXISTS 表名;
TRUNCATE TABLE 表名;

区别:

sql
DROP:删除整张表,包括结构。
TRUNCATE:清空数据,保留表结构。
DELETE:删除数据,可带 WHERE

3.3 字段类型速记

数值:

类型 常用场景
TINYINT 状态、性别、很小整数
INT 普通整数 ID、年龄等
BIGINT 大整数、雪花 ID
DECIMAL(m,d) 金额、精确小数
DOUBLE 普通浮点数

字符串:

类型 区别
CHAR(n) 定长,适合长度固定,如性别、状态码
VARCHAR(n) 变长,最常用,如姓名、手机号
TEXT 大文本

日期时间:

类型 含义
DATE 年月日
TIME 时分秒
DATETIME 年月日时分秒
TIMESTAMP 时间戳,和时区相关

常用选择:

sql
姓名:VARCHAR
年龄:INT
金额:DECIMAL
创建时间:DATETIME
状态:TINYINT

3.4 修改表结构

添加字段:

sql
ALTER TABLE 表名 ADD 字段名 类型 [约束] [COMMENT '注释'];

修改字段类型:

sql
ALTER TABLE 表名 MODIFY 字段名 新类型;

修改字段名和类型:

sql
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新类型;

删除字段:

sql
ALTER TABLE 表名 DROP 字段名;

修改表名:

sql
ALTER TABLE 表名 RENAME TO 新表名;

4. DML:增删改数据

4.1 INSERT

指定字段插入:

sql
INSERT INTO 表名(字段1, 字段2) VALUES(值1, 值2);

全部字段插入:

sql
INSERT INTO 表名 VALUES(值1, 值2, 值3);

批量插入:

sql
INSERT INTO 表名(字段1, 字段2)
VALUES
(值1, 值2),
(值1, 值2),
(值1, 值2);

易错点:

cpp
字符串和日期要加引号。
字段数量和值数量要一致。
自增主键可以写 NULL 或不写。

4.2 UPDATE

sql
UPDATE 表名 SET 字段1 =1, 字段2 =2 WHERE 条件;

示例:

sql
UPDATE emp SET age = 20 WHERE id = 1;

危险点:

sql
UPDATE emp SET age = 20;

这会修改整张表。


4.3 DELETE

sql
DELETE FROM 表名 WHERE 条件;

示例:

sql
DELETE FROM emp WHERE id = 1;

危险点:

sql
DELETE FROM emp;

这会删除整张表数据。


5. DQL:查询核心

5.1 SELECT 完整语法

sql
SELECT 字段列表
FROM 表名
WHERE 条件
GROUP BY 分组字段
HAVING 分组后条件
ORDER BY 排序字段 ASC|DESC
LIMIT 起始索引, 查询条数;

执行顺序理解:

rust
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT

考试/面试最常问:

sql
WHERE 是分组前过滤。
HAVING 是分组后过滤。

5.2 基础查询

查询所有字段:

sql
SELECT * FROM 表名;

查询指定字段:

sql
SELECT 字段1, 字段2 FROM 表名;

去重:

sql
SELECT DISTINCT 字段 FROM 表名;

别名:

sql
SELECT 字段 AS 别名 FROM 表名;
SELECT 字段 别名 FROM 表名;

5.3 WHERE 条件查询

比较运算:

sql
=       等于
<>!= 不等于
> >= < <=
BETWEEN1 AND2
IN (...)
IS NULL
IS NOT NULL

逻辑运算:

sql
AND
OR
NOT

模糊查询:

sql
LIKE
_  匹配单个字符
%  匹配任意多个字符

示例:

sql
SELECT * FROM emp WHERE age BETWEEN 18 AND 30;
SELECT * FROM emp WHERE name LIKE '张%';
SELECT * FROM emp WHERE name LIKE '_三';
SELECT * FROM emp WHERE dept_id IN (1, 2, 3);
SELECT * FROM emp WHERE id IS NOT NULL;

5.4 聚合函数

函数 作用
COUNT(*) 统计行数
MAX() 最大值
MIN() 最小值
AVG() 平均值
SUM() 求和

示例:

sql
SELECT COUNT(*) FROM emp;
SELECT AVG(age) FROM emp;
SELECT MAX(salary), MIN(salary) FROM emp;

注意:

sql
聚合函数一般会忽略 NULLCOUNT(*) 常用于统计总行数。

5.5 GROUP BY 分组

sql
SELECT 分组字段, 聚合函数
FROM 表名
WHERE 分组前条件
GROUP BY 分组字段
HAVING 分组后条件;

示例:

sql
SELECT dept_id, COUNT(*)
FROM emp
GROUP BY dept_id;

带条件:

sql
SELECT dept_id, AVG(salary)
FROM emp
WHERE age > 20
GROUP BY dept_id
HAVING AVG(salary) > 5000;

易错点:

sql
WHERE 后面不能直接写聚合函数条件。
聚合函数条件要写在 HAVING 后面。

5.6 ORDER BY 排序

sql
SELECT * FROM emp ORDER BY age ASC;
SELECT * FROM emp ORDER BY age DESC;
SELECT * FROM emp ORDER BY age DESC, entrydate ASC;

默认升序:ASC。降序:DESC


5.7 LIMIT 分页

sql
SELECT * FROM 表名 LIMIT 起始索引, 查询条数;

第一页,每页 10 条:

sql
SELECT * FROM emp LIMIT 0, 10;

第 n 页,每页 size 条:

text
起始索引 = (页码 - 1) * 每页条数
sql
SELECT * FROM emp LIMIT (page - 1) * size, size;

MySQL 中也可以写:

sql
SELECT * FROM emp LIMIT 10;

表示查前 10 条。


6. DCL:用户和权限

创建用户:

sql
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';

修改密码:

sql
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';

删除用户:

sql
DROP USER '用户名'@'主机名';

查看权限:

sql
SHOW GRANTS FOR '用户名'@'主机名';

授权:

sql
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';

撤销权限:

sql
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';

示例:

sql
GRANT ALL ON db01.* TO 'test'@'%';

记忆:

markdown
% 表示任意主机都可以连接。
*.* 表示所有数据库的所有表。

7. 约束

约束用于保证表中数据正确、有效、完整。

约束 关键字 含义
非空约束 NOT NULL 不能为 NULL
唯一约束 UNIQUE 不能重复
主键约束 PRIMARY KEY 非空且唯一
默认约束 DEFAULT 不传值时用默认值
检查约束 CHECK 限制取值范围
外键约束 FOREIGN KEY 建立表关系

常见建表:

sql
CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    phone VARCHAR(20) UNIQUE,
    age INT CHECK(age > 0 AND age <= 120),
    status TINYINT DEFAULT 1
);

外键:

sql
ALTER TABLE 子表
ADD CONSTRAINT 外键名
FOREIGN KEY (子表字段) REFERENCES 主表(主表字段);

删除外键:

sql
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;

外键删除/更新行为:

行为 含义
RESTRICT 有关联数据则不允许删除/更新
CASCADE 主表变,子表跟着变
SET NULL 主表删除/更新后,子表外键设为 NULL

8. 多表查询

8.1 表关系

关系 例子 实现方式
一对多 部门-员工 多的一方加外键
多对多 学生-课程 建中间表,两个外键
一对一 用户-用户详情 任意一方加唯一外键

8.2 笛卡尔积

多表查询如果没有连接条件,会产生笛卡尔积:

sql
SELECT * FROM emp, dept;

正确写法要加连接条件:

sql
SELECT *
FROM emp, dept
WHERE emp.dept_id = dept.id;

8.3 内连接

隐式内连接:

sql
SELECT 字段
FROM1, 表2
WHERE1.字段 =2.字段;

显式内连接:

sql
SELECT 字段
FROM1
INNER JOIN2 ON1.字段 =2.字段;

内连接含义:

text
只查询两张表都匹配上的数据。

8.4 外连接

左外连接:

sql
SELECT 字段
FROM 左表
LEFT JOIN 右表 ON 条件;

右外连接:

sql
SELECT 字段
FROM 左表
RIGHT JOIN 右表 ON 条件;

记忆:

sql
LEFT JOIN:保留左表全部数据。
RIGHT JOIN:保留右表全部数据。

8.5 自连接

自己连接自己,常见于员工和领导在同一张表:

sql
SELECT e.name 员工, m.name 领导
FROM emp e
LEFT JOIN emp m ON e.manager_id = m.id;

8.6 UNION

sql
SELECT 字段 FROM1
UNION
SELECT 字段 FROM2;
sql
SELECT 字段 FROM1
UNION ALL
SELECT 字段 FROM2;

区别:

sql
UNION:去重。
UNION ALL:不去重,效率更高。

8.7 子查询

子查询就是 SQL 中嵌套 SQL。

标量子查询:返回一个值。

sql
SELECT * FROM emp WHERE salary > (SELECT AVG(salary) FROM emp);

列子查询:返回一列。

sql
SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE name LIKE '%研发%');

行子查询:返回一行多列。

sql
SELECT * FROM emp
WHERE (salary, manager_id) = (SELECT salary, manager_id FROM emp WHERE name = '张三');

表子查询:返回多行多列。

sql
SELECT *
FROM (SELECT * FROM emp WHERE entrydate > '2020-01-01') t;

9. 事务

事务:一组操作要么全部成功,要么全部失败。

典型场景:转账。

css
A 扣钱成功,B 加钱也必须成功。
中间任意一步失败,都要回滚。

事务控制:

sql
START TRANSACTION;
-- SQL操作
COMMIT;
ROLLBACK;

关闭自动提交:

sql
SELECT @@autocommit;
SET @@autocommit = 0;
COMMIT;
ROLLBACK;

ACID:

特性 含义
原子性 Atomicity 要么都成功,要么都失败
一致性 Consistency 事务前后数据合法一致
隔离性 Isolation 并发事务之间互不干扰
持久性 Durability 提交后数据永久保存

并发事务问题:

问题 含义
脏读 读到别人未提交的数据
不可重复读 同一事务两次读同一行结果不同
幻读 同一事务两次查同一范围,行数不同

隔离级别:

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED 可能 可能 可能
READ COMMITTED 不会 可能 可能
REPEATABLE READ 不会 不会 可能/被 InnoDB 处理
SERIALIZABLE 不会 不会 不会

MySQL InnoDB 默认:

text
REPEATABLE READ,可重复读。

查看和设置隔离级别:

sql
SELECT @@TRANSACTION_ISOLATION;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

第二部分:进阶原理必会


10. MySQL 体系结构

从上到下:

rust
连接层 -> 服务层 -> 引擎层 -> 存储层
作用
连接层 连接处理、认证、权限校验
服务层 SQL 解析、优化、内置函数、执行计划
引擎层 真正负责数据存储和读取
存储层 数据、日志、索引等落盘

关键点:

text
索引是在存储引擎层实现的。
存储引擎是基于表的,不是基于库的。

11. 存储引擎

查看支持的存储引擎:

sql
SHOW ENGINES;

建表指定引擎:

sql
CREATE TABLE 表名 (...) ENGINE = InnoDB;

三大引擎对比:

引擎 特点 场景
InnoDB 支持事务、行锁、外键,默认引擎 绝大多数业务表
MyISAM 不支持事务和外键,只支持表锁,读快 读多写少、老系统
Memory 数据存在内存,速度快,断电丢失 临时表、缓存

面试回答:InnoDB 和 MyISAM 区别:

markdown
1. InnoDB 支持事务,MyISAM 不支持。
2. InnoDB 支持行锁,MyISAM 主要支持表锁。
3. InnoDB 支持外键,MyISAM 不支持。
4. InnoDB 更适合高并发读写,MyISAM 更偏读多写少。

InnoDB 逻辑存储结构:

rust
表空间 ->->->->

重点记:

text
InnoDB 页默认 16KB。
区默认 1MB。
数据最终按行存储。

12. 索引

索引:帮助 MySQL 高效获取数据的有序数据结构。

优点:

text
提高查询效率,降低 IO 成本。
可降低排序成本。

缺点:

sql
占用磁盘空间。
降低 INSERTUPDATEDELETE 效率。

常见索引结构:

结构 特点
B+Tree 最常见,适合范围查询和排序
Hash 等值查询快,不支持范围查询
R-Tree 空间索引
Full-text 全文索引

默认重点:

css
平时说 MySQL 索引,一般指 B+Tree 索引。

12.1 为什么用 B+Tree

B+Tree 特点:

markdown
1. 非叶子节点只存索引,不存真实数据。
2. 所有数据都在叶子节点。
3. 叶子节点之间形成双向链表。
4. 树高度低,磁盘 IO 少。
5. 适合范围查询和排序。

二叉树/红黑树的问题:

text
数据量大时树太高,查询磁盘 IO 多。
顺序插入时普通二叉树可能退化成链表。

B-Tree 和 B+Tree 区别:

css
B-Tree:非叶子节点和叶子节点都可能存数据。
B+Tree:数据都在叶子节点,非叶子节点只做索引。

12.2 索引分类

按字段特性:

类型 含义
主键索引 主键自动创建
唯一索引 索引列值不能重复
普通索引 普通加速查询
全文索引 文本检索

按字段个数:

text
单列索引:一个字段。
联合索引:多个字段组合。

按 InnoDB 存储方式:

类型 含义
聚集索引 数据和索引放一起,叶子节点保存整行数据
二级索引 叶子节点保存主键值,需要时再回表

重点:

text
InnoDB 表一定有且只有一个聚集索引。
主键索引通常就是聚集索引。
二级索引查不到完整数据时,需要通过主键再查一次,这叫回表。

12.3 索引语法

创建索引:

sql
CREATE INDEX 索引名 ON 表名(字段名);

创建唯一索引:

sql
CREATE UNIQUE INDEX 索引名 ON 表名(字段名);

联合索引:

sql
CREATE INDEX idx_name_age ON user(name, age);

查看索引:

sql
SHOW INDEX FROM 表名;

删除索引:

sql
DROP INDEX 索引名 ON 表名;

13. 索引使用规则和失效情况

13.1 最左前缀法则

联合索引:

sql
CREATE INDEX idx_user_name_age_status ON user(name, age, status);

可以走索引:

sql
WHERE name = '张三'
WHERE name = '张三' AND age = 20
WHERE name = '张三' AND age = 20 AND status = 1

不一定完整走索引:

sql
WHERE age = 20
WHERE status = 1
WHERE age = 20 AND status = 1

口诀:

text
联合索引从最左边字段开始连续使用,中间不能断。

13.2 范围查询影响后续字段

sql
WHERE name = '张三' AND age > 18 AND status = 1

可能出现:

text
name、age 用到索引,status 不一定充分利用。

建议:

text
联合索引中,等值查询字段尽量放前面,范围查询字段尽量放后面。

13.3 常见索引失效

  1. 对索引列进行函数或运算:
sql
WHERE SUBSTRING(phone, 10, 2) = '15'
WHERE age + 1 = 20
  1. 字符串不加引号:
sql
WHERE phone = 13800000000

正确:

sql
WHERE phone = '13800000000'
  1. LIKE 左模糊:
sql
WHERE name LIKE '%三'
WHERE name LIKE '%三%'

可以利用索引的形式:

sql
WHERE name LIKE '张%'
  1. OR 条件两边不是都有索引:
sql
WHERE id = 1 OR name = '张三'

如果 name 没索引,可能导致索引失效。

  1. 数据分布影响:
text
如果 MySQL 判断全表扫描更快,也可能不走索引。

13.4 覆盖索引

覆盖索引:查询需要的字段在索引里已经都有,不需要回表。

sql
CREATE INDEX idx_user_name_age ON user(name, age);

可能覆盖:

sql
SELECT name, age FROM user WHERE name = '张三';

可能回表:

sql
SELECT * FROM user WHERE name = '张三';

优化建议:

sql
尽量避免 SELECT *。
能查需要字段,就不要查全部字段。

13.5 索引设计原则

适合建索引:

markdown
1. 经常出现在 WHERE、ORDER BY、GROUP BY 的字段。
2. 区分度高的字段,如手机号、身份证号。
3. 多表连接的关联字段。
4. 查询频繁的大表字段。

不适合建索引:

markdown
1. 数据量很小的表。
2. 经常更新的字段。
3. 区分度低的字段,如性别、状态。
4. 很少用于查询条件的字段。

14. SQL 性能分析

14.1 查看执行频率

sql
SHOW GLOBAL STATUS LIKE 'Com_______';

可以大致看当前数据库是读多还是写多。


14.2 慢查询日志

作用:记录执行慢的 SQL。

查看是否开启:

sql
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';

配置示例:

ini
slow_query_log=1
long_query_time=2

意思:执行超过 2 秒的 SQL 记录到慢查询日志。


14.3 EXPLAIN

查看 SQL 执行计划:

sql
EXPLAIN SELECT * FROM user WHERE id = 1;

重点字段:

字段 看什么
id 查询执行顺序
select_type 查询类型
type 连接访问类型,越靠前越好
possible_keys 可能用到的索引
key 实际用到的索引
key_len 索引使用长度
rows 预估扫描行数
Extra 额外信息

type 常见顺序,从好到差:

sql
system > const > eq_ref > ref > range > index > all

重点:

sql
ALL 表示全表扫描,通常需要重点优化。

15. SQL 优化速记

15.1 INSERT 优化

powershell
批量插入优于一条条插入。
手动提交事务优于每条自动提交。
主键顺序插入优于乱序插入。
大批量导入可用 LOAD DATA

批量插入:

sql
INSERT INTO user(name, age) VALUES
('a', 18), ('b', 19), ('c', 20);

15.2 主键优化

建议:

text
主键长度尽量短。
主键尽量顺序插入。
尽量不要用无序 UUID 当主键。

原因:

text
InnoDB 聚集索引按主键组织数据,无序主键容易导致页分裂,影响性能。

15.3 ORDER BY 优化

优化方向:

powershell
让排序字段尽量走索引。
避免出现 Using filesort。

联合索引顺序要和排序顺序匹配。


15.4 GROUP BY 优化

sql
GROUP BY 字段可以建立索引。
分组前尽量用 WHERE 先过滤,减少参与分组的数据量。

15.5 LIMIT 深分页优化

低效写法:

sql
SELECT * FROM user LIMIT 1000000, 10;

优化思路:

sql
SELECT * FROM user
WHERE id > 1000000
LIMIT 10;

或先查主键,再回表:

sql
SELECT u.*
FROM user u
JOIN (
    SELECT id FROM user ORDER BY id LIMIT 1000000, 10
) t ON u.id = t.id;

15.6 COUNT 优化

常见:

sql
SELECT COUNT(*) FROM 表名;

记忆:

scss
COUNT(*) 一般是推荐写法。
COUNT(字段) 不统计 NULL。

15.7 UPDATE 优化

sql
UPDATEWHERE 条件字段尽量有索引。
否则可能从行锁升级成更多范围的锁,影响并发。

示例:

sql
UPDATE user SET name = '张三' WHERE id = 1;

16. 视图、存储过程、函数、触发器

16.1 视图

视图是虚拟表,本身不直接存数据,数据来自查询结果。

创建:

sql
CREATE VIEW 视图名 AS SELECT 语句;

查询:

sql
SELECT * FROM 视图名;

删除:

sql
DROP VIEW 视图名;

作用:

sql
简化复杂 SQL。
隐藏敏感字段。
统一查询口径。

16.2 存储过程

存储过程是一组预先编译好的 SQL 语句集合。

sql
DELIMITER $
CREATE PROCEDURE p1()
BEGIN
    SELECT COUNT(*) FROM emp;
END$
DELIMITER ;

CALL p1();

参数类型:

类型 含义
IN 输入参数
OUT 输出参数
INOUT 既输入又输出

16.3 触发器

触发器:在 INSERTUPDATEDELETE 前后自动执行。

sql
CREATE TRIGGER 触发器名
BEFORE INSERT ON 表名
FOR EACH ROW
BEGIN
    -- SQL
END;

常用场景:

text
日志记录、数据校验、同步冗余字段。

17. 锁

锁的目的:解决并发访问下的数据安全问题。

按粒度:

范围 特点
全局锁 整个数据库实例 备份时常用
表级锁 整张表 开销小,冲突大
行级锁 某些行 并发高,开销大

17.1 全局锁

加锁:

sql
FLUSH TABLES WITH READ LOCK;

释放:

sql
UNLOCK TABLES;

作用:

text
让整个库处于只读状态,常用于一致性备份。

17.2 表级锁

表锁:

sql
LOCK TABLES 表名 READ;
LOCK TABLES 表名 WRITE;
UNLOCK TABLES;

元数据锁 MDL:

text
对表进行增删改查时自动加 MDL 读锁。
修改表结构时自动加 MDL 写锁。
作用是防止查询过程中表结构被别人改掉。

意向锁:

text
用于协调行锁和表锁,表示表中某些行将要被加锁。

17.3 行级锁

InnoDB 支持行级锁。

常见:

含义
行锁 Record Lock 锁一行记录
间隙锁 Gap Lock 锁记录之间的间隙
临键锁 Next-Key Lock 行锁 + 间隙锁

重点:

text
行锁是加在索引上的。
如果查询条件没有走索引,可能扫描更多数据,锁范围变大。

18. InnoDB 与 MVCC

18.1 InnoDB 内存结构

常见组成:

ruby
Buffer Pool:缓存数据页和索引页。
Change Buffer:缓存普通二级索引变更。
Adaptive Hash Index:自适应哈希索引。
Log Bufferredo log 缓冲。

最重要:

text
Buffer Pool 是 InnoDB 性能的核心缓存区域。

18.2 redo log 与 undo log

redo log:

text
保证事务持久性。
记录“做了什么修改”。
崩溃恢复时使用。

undo log:

bash
保证事务原子性。
记录“修改前的数据”。
回滚和 MVCC 都依赖 undo log

对比:

日志 作用
redo log 崩溃恢复,保证已提交事务不丢
undo log 回滚和多版本并发控制

18.3 MVCC

MVCC:多版本并发控制。

作用:

text
在不加锁或少加锁的情况下,实现并发读写,提高性能。

依赖:

bash
隐藏字段 + undo log 版本链 + ReadView

InnoDB 隐藏字段:

字段 作用
DB_TRX_ID 最近修改该记录的事务 ID
DB_ROLL_PTR 指向 undo log 中上一个版本
DB_ROW_ID 隐藏主键,没有主键时生成

ReadView:

text
用于判断当前事务能看到哪个版本的数据。

RC 和 RR 的区别:

sql
READ COMMITTED:每次 SELECT 都生成新的 ReadView。
REPEATABLE READ:事务第一次 SELECT 生成 ReadView,后续复用。

第三部分:运维架构必会


19. MySQL 常用工具

连接:

bash
mysql -h 127.0.0.1 -P 3306 -u root -p

查看服务状态:

bash
mysqladmin -u root -p version
mysqladmin -u root -p variables

查看 binlog:

bash
mysqlbinlog binlog.000001

备份:

bash
mysqldump -u root -p 数据库名 > db.sql
mysqldump -u root -p --all-databases > all.sql

恢复:

bash
mysql -u root -p 数据库名 < db.sql

MySQL 内执行脚本:

sql
SOURCE /path/db.sql;

20. 日志

日志 作用
错误日志 error log 记录启动、停止、严重错误
二进制日志 binlog 记录 DDL 和 DML,不记录 SELECT
查询日志 general log 记录客户端所有操作,默认关闭
慢查询日志 slow query log 记录执行慢的 SQL

20.1 error log

作用:

text
数据库启动失败、运行异常,优先看错误日志。

查看位置:

sql
SHOW VARIABLES LIKE '%log_error%';

20.2 binlog

作用:

markdown
1. 数据恢复。
2. 主从复制。

查看是否开启:

sql
SHOW VARIABLES LIKE '%log_bin%';

格式:

格式 含义
STATEMENT 记录 SQL 语句
ROW 记录每一行数据变更,默认常用
MIXED 混合模式

清理 binlog:

sql
RESET MASTER;
PURGE MASTER LOGS TO 'binlog.000010';
PURGE MASTER LOGS BEFORE '2024-01-01 00:00:00';

20.3 慢查询日志

配置:

ini
slow_query_log=1
long_query_time=2
log_queries_not_using_indexes=1

记忆:

sql
慢查询日志用于定位慢 SQL,是 SQL 优化的入口。

21. 主从复制

主从复制:主库数据变更通过 binlog 同步到从库。

作用:

markdown
1. 主库故障时,从库可顶上。
2. 实现读写分离,减轻主库压力。
3. 可以在从库备份,减少对主库影响。

原理三步:

markdown
1. Master 提交事务时,把变更写入 binlog。
2. Slave IO 线程读取 Master binlog,写入 relay log。
3. Slave SQL 线程重放 relay log,使从库数据追上主库。

主库关键配置:

python
server-id=1
read-only=0

创建复制用户:

sql
CREATE USER 'itcast'@'%' IDENTIFIED WITH mysql_native_password BY 'Root@123456';
GRANT REPLICATION SLAVE ON *.* TO 'itcast'@'%';
SHOW MASTER STATUS;

从库关键配置:

python
server-id=2
read-only=1

从库设置主库信息,MySQL 8.0.23 后:

sql
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='主库IP',
SOURCE_USER='复制用户',
SOURCE_PASSWORD='密码',
SOURCE_LOG_FILE='binlog文件名',
SOURCE_LOG_POS=位置;

启动复制:

sql
START REPLICA;
SHOW REPLICA STATUS;

旧版本写法:

sql
START SLAVE;
SHOW SLAVE STATUS;

22. 分库分表

为什么需要分库分表:

text
单库单表数据量过大后,会出现磁盘 IO、网络 IO、CPU 瓶颈。
分库分表的核心是:把数据分散存储,降低单库单表压力。

拆分方式:

方式 依据 特点
垂直分库 按业务拆表到不同库 每个库表不同,数据不同,并集为全量
垂直分表 按字段拆成不同表 表结构不同,通过主键关联
水平分库 按字段规则把数据拆到不同库 库结构相同,数据不同,并集为全量
水平分表 按字段规则把一张表拆成多张表 表结构相同,数据不同,并集为全量

例子:

text
垂直分库:用户库、订单库、商品库分开。
垂直分表:商品基本信息和商品详情分开。
水平分库:订单按用户ID取模分到不同库。
水平分表:订单表按月份或ID范围拆成多张表。

实现技术:

text
ShardingJDBC:应用层分库分表组件。
MyCat:数据库中间件,对应用伪装成一个 MySQL。

23. MyCat 与读写分离

MyCat:数据库中间件,客户端连接 MyCat,MyCat 再根据规则转发 SQL 到真实数据库。

核心概念:

概念 含义
schema 逻辑库
table 逻辑表
dataNode 数据节点
dataHost 数据主机
rule 分片规则

常见端口:

yaml
8066:MyCat 数据访问端口。
9066:MyCat 管理端口。

读写分离:

text
写操作走主库。
读操作走从库。
目的:降低主库压力,提高系统整体读能力。

一主一从:

text
Master 负责写。
Slave 负责读。
Master 通过 binlog 同步数据到 Slave。

双主双从:

text
两个主库互为主从,下面再挂从库。
可以提高可用性,但配置更复杂。

第四部分:高频易错点和面试表达


24. 必背执行顺序

SQL 写法顺序:

sql
SELECT ...
FROM ...
WHERE ...
GROUP BY ...
HAVING ...
ORDER BY ...
LIMIT ...;

SQL 执行理解顺序:

rust
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT

25. WHERE 和 HAVING

对比 WHERE HAVING
执行时机 分组前 分组后
能否使用聚合函数 一般不能 可以
作用对象 原始行数据 分组结果

示例:

sql
SELECT dept_id, COUNT(*)
FROM emp
WHERE age > 18
GROUP BY dept_id
HAVING COUNT(*) > 5;

26. DELETE、TRUNCATE、DROP

命令 作用 是否保留表结构
DELETE 删除部分或全部数据 保留
TRUNCATE 清空整表数据 保留
DROP 删除整张表 不保留

27. 内连接、外连接

cpp
内连接:只要两边匹配上的数据。
左外连接:左表全部保留,右表匹配不上补 NULL。
右外连接:右表全部保留,左表匹配不上补 NULL

28. 索引口诀

sql
大表高频查,考虑建索引。
whereorder bygroup byjoin 字段优先。
联合索引看最左,范围之后要小心。
函数运算会失效,字符串记得加引号。
LIKE 百分号别放左,SELECT 星号少使用。
索引不是越多越好,增删改也要付成本。

29. 事务和锁的关系

text
事务解决一组操作的一致性问题。
锁解决并发访问时的数据安全问题。
事务隔离性通常依赖锁和 MVCC 实现。

30. InnoDB 面试表达

可以这样说:

bash
InnoDB 是 MySQL 默认存储引擎,支持事务、行级锁和外键,适合高并发业务场景。
它使用 B+Tree 组织索引,主键索引是聚集索引,叶子节点保存整行数据;二级索引叶子节点保存主键值,必要时需要回表。
InnoDB 通过 redo log 保证持久性,通过 undo log 支持回滚和 MVCC,通过 MVCC 在读写并发场景下提高性能。

31. 主从复制面试表达

可以这样说:

bash
MySQL 主从复制基于 binlog。主库提交事务后把 DDL 和 DML 变更写入 binlog;从库 IO 线程读取主库 binlog 写入 relay log;从库 SQL 线程重放 relay log,从而保持主从数据同步。主从复制常用于读写分离、故障切换和备份。

32. 分库分表面试表达

可以这样说:

text
当单库单表数据量过大,出现 IO、CPU 或连接压力时,可以通过分库分表把数据分散存储。垂直拆分按业务或字段拆,水平拆分按某个字段规则拆。垂直拆分解决业务耦合和宽表问题,水平拆分主要解决单表数据量过大的问题。

33. 最后总口诀

sql
基础 SQL:DDL建表,DML改数,DQL查询,DCL管权。
查询顺序:from where group having select order limit。
多表查询:先想表关系,再写连接条件,避免笛卡尔积。
事务重点:ACID、并发问题、隔离级别。
索引重点:B+Tree、最左前缀、回表、覆盖索引、索引失效。
优化重点:慢查询日志 + EXPLAIN + 合理建索引。
InnoDB重点:事务、行锁、外键、redo、undo、MVCC。
运维重点:binlog、主从复制、读写分离、分库分表。

相关文章