ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MySQL从入门到高级:笔记之外的可落地方案与避坑指南

MySQL从入门到高级:笔记之外的可落地方案与避坑指南

简介:一份名为MySQL数据库入门到高级笔记的PDF资料,由博主原创的三篇万字教程整合而成,并搭配多张思维导图梳理知识脉络,覆盖从零基础到进阶应用的完整学习路径。内容先讲MySQL服务的启动关闭、登录退出,以及数据库和数据表的基本操作;随后以查询为主线,细讲单表查询、多表连接、分组查询、模糊查询、排序、别名、聚合统计等常用写法;高级部分深入视图、存储过程、索引、触发器、事务、安全管理、数据库备份与还原,并给出性能优化思路,覆盖常见开发与面试场景。资源为单个PDF文件,压缩包约18.4MB,全文累计超65000字,适合离线阅读、反复翻阅与查漏补缺,便于按需查阅特定知识点。已有1571人学习下载,无论新手入门还是开发者快速回顾,都能从中获取系统完整的MySQL知识框架,上手难度低,资料密度高。

1. 从一份 PDF 笔记说开去:MySQL 入门到高级到底该怎么学

MySQL 数据库入门到高级笔记 pdf 版本,这类资源在技术圈里流传很广,但绝大多数人下载之后的结果是「存进网盘吃灰」。原因很简单:PDF 是静态的,而 MySQL 是动态的——你对着 PDF 看完索引章节,不等于你会建索引;你背下存储过程语法,不等于你能在线上环境排错。所以这篇文章不打算帮你推荐某一份具体笔记,而是想讲清楚:拿到一份 MySQL 入门到高级 PDF 之后,怎么把它变成一条可落地的学习路径,以及这条路径上最常翻车的位置在哪里。文章面向两类人——刚装好 MySQL 还不知道怎么下手的新手,以及已经写过几年 SQL 但总觉得知识零散、想系统补一遍的开发者。下面每一章都按「先立理论、再给可复现操作」的顺序来写,你完全可以照着敲。

需要先说明的是:MySQL 入门到高级的学习材料,无论叫笔记还是教程 PDF,核心知识框架基本是一致的,无非是基础 SQL、数据类型、索引、事务与锁、存储过程、视图、主从复制、性能调优这几大块。区别在于讲得深不深、例子真不真、坑提得多不多。所以本文默认你已经有一份章节完整的 PDF,然后在此基础上告诉你每个章节应该怎么学、用什么命令验证、卡住了去哪里排查。

2. 学习路线设计:区别于泛读 PDF 的三层递进

2.1 资源包的常见章节结构(新手照这个顺序读)

一份合格的 MySQL 入门到高级 PDF,通常会把内容切成三层:第一层是「能跑通」,包括安装、建库建表、增删改查、数据类型与约束;第二层是「能干活」,包括索引、事务、视图、存储过程、触发器、权限管理;第三层是「能排障」,包括 EXPLAIN 执行计划分析、慢查询日志、主从复制、备份恢复、性能调优参数。这个分层不是随便排的,它对应的是你在真实工作中会遇到的三个递进场景:先能把数据存进去取出来,再能在业务里正确地操作数据,最后才能在数据量变大、并发变高之后让系统不崩。

我见过很多人学 MySQL 的方式是「从 PDF 第一页翻到最后一页」,这种线性阅读对一本 400 页的入门到高级笔记来说效率极低。更好的做法是交叉读:基础 SQL 部分逐章精读,索引和事务部分先读概念再看例子最后动手复现,存储过程和主从复制部分直接跳到案例章节,遇到看不懂的语法再回翻。只要你目标明确,PDF 不需要从头读到尾,搜索和索引功能本身就是学习工具。

2.2 为什么不是所有 PDF 都适合「从入门到高级」

市面上名字叫「MySQL 入门到高级笔记」的 PDF 至少有三种:第一种是官方文档的中文精简版,语法准确但例子枯燥,适合工作后当字典查;第二种是培训机构的课程讲义,章节齐全、案例丰富,但往往针对某个特定版本写成,版本差异会导致部分命令失效;第三种是个人博客合集打包,优点是口语化、坑讲得细,缺点是知识体系可能不完整,比如有的笔记讲完索引就跳去讲面试题,事务和锁整章缺失。

判断一份 PDF 值不值得精读,我的做法是先看三处:第一处是目录里有没有「事务隔离级别」和「锁」章节,MySQL 的高级感一半体现在这里;第二处是索引章节有没有讲联合索引的最左前缀原则和回表,只讲 B+ 树结构不讲应用场景的索引章节等于没写;第三处是看所有 SQL 示例有没有标注版本,像 MySQL 8.0 里窗口函数、CTE、mysql_native_password 默认关闭这些变化,老笔记里完全不提就会把你带进坑。如果你手里的 PDF 这三处都不过关,建议只把它当习题册刷,理论部分另外找资料补。

提示:判断一份笔记的「高级」含量,不是看目录里有没有「优化」「调优」字样,而是看它有没有回答一个问题——为什么这条 SQL 慢?以及你能用什么命令把它变快。

2.3 从 PDF 到本地环境:照着笔记动手的第一步

拿到 PDF 之后的第一件事不是读,而是装环境。没有本地 MySQL 环境,所有笔记里的内容都只是「看起来懂了」。下面给出 Linux(Ubuntu 系)和 Windows 两条安装路径。

Linux 下安装 MySQL 8.0 的常见做法是使用官方 apt 仓库:

# 更新包索引 sudo apt update # 安装 MySQL 服务端与客户端 sudo apt install mysql-server mysql-client -y # 查看安装后的版本 mysql --version # 启动服务并设为开机自启 sudo systemctl start mysql sudo systemctl enable mysql # 查看服务运行状态 sudo systemctl status mysql

这段命令执行完后,MySQL 服务应该已经跑起来了。注意 Ubuntu 上安装 mysql-server 后 root 账户默认使用 auth_socket 插件认证,也就是说你在终端用sudo mysql可以直接进去,但用 root 加密码去连会失败。这是笔记里经常忽略的坑,后面第 4 章会专门讲。

Windows 下的安装相对直观:去 MySQL 官网下载安装包,选 MySQL Community Server 8.0.x,安装时选择 Developer Default 或 Server only,配置端口默认 3306,认证方式建议选「Use Legacy Password Encryption」以外的选项——如果你要兼容老客户端,就得选第一个,但 MySQL 8.0 默认的 caching_sha2_password 在新客户端下更安全。装完后在系统环境变量 PATH 里加上 MySQL 的 bin 目录,否则 cmd 里敲mysql会提示找不到命令。

环境装好只是第一步。我强烈建议你再装一个图形客户端,MySQL Workbench 或者 Navicat 都行,但学习阶段不要依赖它——PDF 笔记里的 SQL 你必须在命令行里敲一遍才能形成肌肉记忆。Workbench 用来做 ER 图、导入导出、可视化 EXPLAIN 结果,这些是命令行做不到的,两者搭配使用:命令行负责练基本功,图形工具负责提高效率。

3. 用 PDF 版笔记搭建本地学习环境:建库建表、增删改查与存储过程的可复现实验

3.1 初始化数据库并设置 root 密码

装好 MySQL 后的第一件事是初始化 root 密码。前面提到 Ubuntu 下 root 默认走 auth_socket,你要把它改成密码登录:

# 以 sudo 身份进入 MySQL(此时不需要密码) sudo mysql -- 切换到 mysql 系统库 USE mysql; -- 将 root 的认证方式改为 caching_sha2_password 并设置密码 ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '你的强密码'; FLUSH PRIVILEGES; -- 退出后测试密码登录 EXIT;

进入 MySQL 后,第一组必须亲手敲的命令是查看系统信息和当前库状态:

-- 查看版本 SELECT VERSION(); -- 查看当前用户 SELECT CURRENT_USER(); -- 查看所有数据库 SHOW DATABASES; -- 查看 MySQL 的默认存储引擎 SHOW ENGINES;

这四条命令能帮你确认环境是好的,同时建立对 MySQL 系统库的初步感知——information_schema、mysql、performance_schema 这几个库是系统自带的,不要动它们。

3.2 建库建表与增删改查:把笔记里的语法变成手指记忆

基础 SQL 部分最值得动手的是一整套「建库 → 建表 → 插数据 → 查数据 → 改数据 → 删数据」流程。我建议所有初学者照下面这个完整 demo 敲一遍,不要复制,一个个字符敲。

-- 创建数据库:字符集用 utf8mb4,这是 MySQL 8.0 的默认值,老笔记里写 utf8 的要改 CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci; -- 使用该库 USE shop; -- 创建用户表 CREATE TABLE t_user ( id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', username VARCHAR(32) NOT NULL COMMENT '用户名', age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINE = InnoDB COMMENT '用户表'; -- 插入:单行与多行 INSERT INTO t_user (username, age) VALUES ('zhangsan', 23); INSERT INTO t_user (username, age) VALUES ('lisi', 25), ('wangwu', 28); -- 查询:条件、排序、分页 SELECT id, username, age, created_at FROM t_user WHERE age > 20 ORDER BY age DESC LIMIT 10; -- 更新 UPDATE t_user SET age = 26 WHERE username = 'zhangsan'; -- 删除:按条件删,注意不要不加 WHERE 全删掉 DELETE FROM t_user WHERE username = 'wangwu';

这段代码是整个 MySQL 学习路径的基石,也是你以后写业务代码的模板。几个容易忽略的参数需要说明:INT UNSIGNED表示无符号整数,能存 42 亿条记录,这是线上表最常见的写法;TINYINT UNSIGNED最大 255,存年龄足够;DEFAULT CURRENT_TIMESTAMP让数据库自动记录创建时间,不需要应用层传入;UNIQUE KEY uk_username给 username 加了唯一约束,重复插入会报 Duplicate entry 错误。

折腾完这组命令,你应该对「数据库增删改查」这个热搜词有一个完整认知了。PDF 笔记里这个环节通常还会讲 BETWEEN、LIKE、IN、JOIN 等高级查询语法,我建议你把这些语法全部往 t_user 上套着写一遍,比如:

-- 模糊查询 SELECT * FROM t_user WHERE username LIKE 'zhang%'; -- 范围查询 SELECT * FROM t_user WHERE id IN (1, 2, 3); -- LEFT JOIN 示例:先建一张订单表 CREATE TABLE t_order ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, user_id INT UNSIGNED NOT NULL, amount DECIMAL(10, 2) NOT NULL DEFAULT 0, PRIMARY KEY (id) ) ENGINE = InnoDB; INSERT INTO t_order (user_id, amount) VALUES (1, 99.90), (2, 199.00), (1, 5.50); -- 查询每个用户的订单总额 SELECT u.username, COALESCE(SUM(o.amount), 0) AS total_amount FROM t_user u LEFT JOIN t_order o ON u.id = o.user_id GROUP BY u.id, u.username ORDER BY total_amount DESC;

LEFT JOIN 和 GROUP BY 是新手翻车重灾区——不加 GROUP BY 直接 SELECT username 和 SUM(amount),在 MySQL 8.0 里直接报错,因为 ONLY_FULL_GROUP_BY 默认开启;老笔记里基于 5.7 之前写的「随便查」在现代版本里全部失效。所以看到 PDF 里 GROUP BY 章节,一定注意它是否提到 sql_mode 这个参数。

3.3 存储过程与触发器:高级笔记的第一个动手门槛

PDF 笔记里到了存储过程和触发器章节,理论看完后必做的一个实验是实现一个「带事务的订单扣库存」过程。这个过程能同时覆盖存储过程语法、事务控制、异常处理三块内容,属于一鱼三吃的经典案例。

-- 修改分隔符,因为存储过程体内部用分号 DELIMITER $$ CREATE PROCEDURE sp_create_order( IN p_user_id INT UNSIGNED, IN p_product_id INT UNSIGNED, IN p_quantity INT UNSIGNED, OUT p_order_id INT UNSIGNED ) BEGIN DECLARE v_stock INT DEFAULT 0; DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END; START TRANSACTION; -- 查询库存并加锁(悲观锁:SELECT ... FOR UPDATE) SELECT stock INTO v_stock FROM t_product WHERE id = p_product_id FOR UPDATE; -- 库存不足直接报错 IF v_stock < p_quantity THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '库存不足'; END IF; -- 扣库存 UPDATE t_product SET stock = stock - p_quantity WHERE id = p_product_id; -- 生成订单 INSERT INTO t_order (user_id, product_id, quantity) VALUES (p_user_id, p_product_id, p_quantity); -- 返回订单号 SET p_order_id = LAST_INSERT_ID(); COMMIT; END$$ DELIMITER ;

这段存储过程的行为逻辑是:开启事务后先用SELECT ... FOR UPDATE锁住商品行,避免并发下超卖;库存不足则抛出 SQLSTATE 45000 信号;一切正常则更新库存、插入订单、提交事务。出现任何异常时由 EXIT HANDLER 回滚并重新抛错。整个过程把事务隔离、行锁、异常处理三个概念串了起来,是 MySQL 高级笔记里最值得动手复现的实验,没有之一。

执行这段代码前需要先建一张 t_product 表,并插入一行数据:

CREATE TABLE t_product ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, product_name VARCHAR(64) NOT NULL, stock INT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (id) ) ENGINE = InnoDB; INSERT INTO t_product (product_name, stock) VALUES ('iPhone 15', 100); -- 调用存储过程 CALL sp_create_order(1, 1, 2, @order_id); -- 查看返回的订单号 SELECT @order_id; -- 查看库存是否被扣减 SELECT * FROM t_product;

关于存储过程,现在业界有一个争议:互联网公司普遍不推荐在业务里大量使用存储过程,因为逻辑分散在数据库里,代码版本管理困难、扩展性差。但这不代表学习阶段可以不学——存储过程是理解事务、游标、异常处理的最佳载体,也是面试里「手写一个存储过程实现 XX 场景」的常见考点。你要学的不是「工作中多用存储过程」,而是「通过存储过程理解数据库执行一个复杂逻辑的全过程」。

4. MySQL 学习中最常见的 5 个踩坑与排查记录

4.1 坑一:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock'

现象:在终端敲mysql -u root -p,报错ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)。

原因:这条报错的全称是「客户端在通过 Unix socket 寻找 MySQL 服务时没找到」,它并不是密码错误。出现这个错误有三种常见原因:MySQL 服务没启动;配置文件里 socket 路径不是 /tmp/mysql.sock;客户端默认用的 socket 路径与服务端不一致。新手最常踩的是第一种——装完 MySQL 后忘记启动服务。

解决:在 Linux 下先确认服务状态:

# 检查服务是否在运行 sudo systemctl status mysql # 如果没运行,启动它 sudo systemctl start mysql # 如果启动失败,查看错误日志 sudo tail -100 /var/log/mysql/error.log

如果服务在运行但仍然报 socket 错误,检查 MySQL 配置文件:

# 查看 socket 配置 cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep socket # 连接时显式指定 socket 路径 mysql -u root -p --socket=/var/run/mysqld/mysqld.sock

这个坑值得专门记录的原因在于:它和后面 4.2 的密码错误容易被混淆,新手一旦看到 error 2002 就以为是密码错了,反复重置密码浪费时间。看到 Can't connect through socket 先查服务状态,再查 socket 路径,最后才考虑密码问题。

4.2 坑二:root 密码忘记了导致登录不上

现象:之前设置过密码但忘了,mysql -u root -p输入错误的密码被拒绝;或者刚装完 MySQL 8.0,根本不知道 root 初始密码是什么。

原因:MySQL 8.0 在安装时不会像 5.7 那样在日志里打印临时密码,Ubuntu 下默认走 auth_socket 认证,你只用知道系统用户是 root 时可以直接进;而 Windows 安装时让你设置密码,但如果你装的是解压版(zip 包)而不是安装版,root 默认是无密码的,或者密码为空但登录被拒绝。

解决:Linux 下最简单的方式是走 auth_socket 跳过密码进 MySQL,然后修改密码:

# 用系统权限进入 MySQL sudo mysql -- 修改 root 的认证方式与密码 ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '新密码'; FLUSH PRIVILEGES; EXIT;

Windows 解压版忘记密码的常见处理步骤是:在 my.ini 配置文件里加上skip-grant-tables,重启 MySQL 服务后免密登录,执行 UPDATE 重置密码,然后删掉该参数再重启。但有一个细节必须注意:MySQL 8.0 下 user 表里 authentication_string 字段存的是哈希值,不能用SET PASSWORD = PASSWORD('xxx')这种老语法,必须用ALTER USER。

注意:开启 skip-grant-tables 等于关掉了所有权限校验,这个期间 MySQL 端口会暴露在网络上,任何能连到你 3306 端口的人都可以免密登录。处理完密码后必须立刻重启 MySQL 并移除该参数,不要在这个状态下挂机过夜。

4.3 坑三:MySQL 8.0 默认认证插件导致客户端连接失败

现象:用 Navicat、老版本 JDBC 驱动或者 DataGrip 连接 MySQL 8.0,报错Authentication plugin 'caching_sha2_password' cannot be loaded或Public Key Retrieval is not allowed。

原因:MySQL 8.0 默认的认证插件从 mysql_native_password 换成了 caching_sha2_password,老客户端不认识这个插件,或者出于安全考虑不主动请求服务端公钥。这是从 5.7 升到 8.0 最容易踩的兼容性问题,也是各种 PDF 笔记里极少提到的变化。

解决:有两个方向。第一个方向是升级客户端——Navicat 16 以上、JDBC 驱动 8.0.x 以上都原生支持;第二个方向是把用户改回老插件,做法如下:

-- 将指定用户的认证插件改回 mysql_native_password ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; FLUSH PRIVILEGES;

但要注意:MySQL 8.4 里 mysql_native_password 被默认禁用,如果你装的是 8.4,需要先在配置文件里显式启用mysql_native_password=ON,否则 ALTER USER 会报错。所以选择哪种方案,取决于你的 MySQL 版本和客户端更新成本,而不是无脑改插件。我个人的建议是:能用新客户端就用新客户端,改插件会把安全等级降回 5.7 时代,治标不治本。

4.4 坑四:ORDER BY 排序结果与预期不符

现象:执行SELECT * FROM t_user ORDER BY age DESC LIMIT 10,结果里出现 age 为 NULL 的行排在最前面;或者对字符串类型的列排序,发现顺序是「10、2、23、3」这种非预期结果。

原因:第一个现象是因为在 MySQL 中 NULL 在升序时排最前、降序时排最后(具体看排序方向),很多人没意识 NULL 也是一种参与排序的值;第二个现象是把 VARCHAR 类型的列存了数字,比如手机号、订单号用字符串存储,排序时按字典序排而不是数值序排。

解决:对 NULL 的排序需求,用ORDER BY age IS NULL, age DESC把空值排到最后;对字符串数字,要么建表时就用数值类型,要么排序时 CAST 转换:

-- 让 NULL 永远排在最后 SELECT * FROM t_user ORDER BY (age IS NULL), age DESC; -- 字符串数字按数值排序 SELECT * FROM t_order WHERE order_no LIKE '2024%' ORDER BY CAST(order_no AS UNSIGNED) DESC;

这个坑在 PDF 笔记里通常只会写「ORDER BY 用于排序」,不会写 NULL 的排序优先级。你只有自己执行之后发现结果「诡异」才会去查文档,这也是为什么我一直强调学 MySQL 必须亲手敲命令——光读笔记根本触发不了对这些细节的追问。

4.5 坑五:MySQL 主从复制中的同步延迟与数据不一致

现象:配置好主从复制后,从库查不到刚在主库插入的数据;或者从库报错Slave I/O for channel '': error connecting to master。

原因:同步延迟的第一大原因是主库的大事务——比如一次 UPDATE 影响了几十万行,binlog 在从库上回放需要时间;第二大原因是从库硬件比主库差、单线程复制跟不上主库写入速度;连接失败则多半是复制账号权限不对、主库没开 binlog、或者防火墙挡了 3306 端口。

解决:先查看从库状态定位问题:

-- 在从库上执行,查看复制状态 SHOW SLAVE STATUS\G

重点看几个字段:Slave_IO_Running和Slave_SQL_Running是否都是 Yes;Seconds_Behind_Master数值是否持续增长;Last_IO_Error/Last_SQL_Error的具体内容。如果 IO 线程报错,检查主库的复制账号是否存在以及能否连通:

# 在主库上查看当前 binlog 文件与位置 SHOW MASTER STATUS; # 测试复制账号能否从从库所在机器连到主库 mysql -h 主库IP -P 3306 -u repl -p'密码' -e "SELECT 1;"

缩小延迟的常见手段包括:把从库的sync_binlog设为 0 或加大间隔、启用并行复制(MySQL 5.7 引入 slave_parallel_workers,8.0 默认开启 MTS)、把大 UPDATE 拆成小批次循环执行、给从库换更好的磁盘。但记住一个原则:主从复制不会自动修复数据不一致,它只能保证「从库按 binlog 顺序回放」,如果你在主库上执行了不带 WHERE 的 DELETE,从库同样会删光。

5. 从入门到高级的进阶验证:索引调优、事务隔离级别与主从复制的可复现实验

5.1 用 EXPLAIN 验证索引是否真的生效

PDF 笔记里的索引章节,理论讲得再详细,都不如一张 EXPLAIN 输出表有说服力。下面用 t_order 表验证「按 user_id 查询」在有无索引时的差距。

-- 先看现在的执行计划(user_id 目前没有索引) EXPLAIN SELECT * FROM t_order WHERE user_id = 1; -- 创建索引 CREATE INDEX idx_user_id ON t_order(user_id); -- 再看创建后的执行计划 EXPLAIN SELECT * FROM t_order WHERE user_id = 1;

第一段 EXPLAIN 的结果中,type字段是 ALL,rows是表的总行数,说明这是全表扫描;第二段执行计划中type变成 ref,key显示 idx_user_id,说明索引生效了。通过这个实验,你能直观理解索引的作用原理:索引让数据库不再逐行扫描整个表,而是通过 B+ 树直接定位到目标行所在的数据页。

进阶一步,验证联合索引的最左前缀原则:

-- 创建联合索引(user_id, amount) CREATE INDEX idx_user_amount ON t_order(user_id, amount); -- 情况一:只查 user_id —— 会走联合索引 EXPLAIN SELECT * FROM t_order WHERE user_id = 1; -- 情况二:只查 amount —— 不会走联合索引(缺少最左列) EXPLAIN SELECT * FROM t_order WHERE amount > 50; -- 情况三:user_id 和 amount 一起查 —— 走联合索引 EXPLAIN SELECT * FROM t_order WHERE user_id = 1 AND amount > 50;

这个实验对应了 PDF 笔记里最容易被忽略的一个点:联合索引 (a, b) 不是两个独立的索引,而是一个「先按 a 排序、再按 b 排序」的复合结构。单独查 b 条件时,数据库无法从该索引中快速定位,只能走全表扫描。很多新手建了联合索引却发现查询还是慢,原因就是 SQL 条件里没带上最左列。

5.2 索引失效的 4 种常见场景验证

索引理论里,「索引什么时候失效」比「索引怎么建」更容易在面试里被问到,也是工作中排查慢 SQL 的必经之路。下面用可复现的 SQL 实验验证常见的失效场景。

-- 场景一:对索引列使用函数(失效) EXPLAIN SELECT * FROM t_order WHERE DATE_FORMAT(created_at, '%Y-%m-%d') = '2025-01-01'; -- 场景二:隐式类型转换(失效) EXPLAIN SELECT * FROM t_user WHERE username = 1234; -- 场景三:LIKE 以 % 开头(失效) EXPLAIN SELECT * FROM t_user WHERE username LIKE '%zhang%'; -- 场景四:OR 连接非索引列(可能导致失效) EXPLAIN SELECT * FROM t_order WHERE user_id = 1 OR amount = 500;

场景一的「正确写法」是把条件改成范围查询,让索引列不被函数包裹:

EXPLAIN SELECT * FROM t_order WHERE created_at >= '2025-01-01 00:00:00' AND created_at < '2025-01-02 00:00:00';

场景二在 MySQL 里有一个特殊表现:如果 username 列是 VARCHAR 类型,而 WHERE 条件里用了数字字面量,MySQL 会把列值转成数字再比较,导致全表扫描。这种问题在代码里更容易出现——比如接口传参没做类型校验,把 userId 当字符串查总表,线上就慢得不行。

执行完这组 EXPLAIN 你会得到一个重要结论:索引不是建完就完事了,SQL 写法是否符合索引结构决定了一切。PDF 笔记里如果只贴 B+ 树结构图、不写这些失效场景,那这个索引章节质量是存疑的。

5.3 事务隔离级别:用两个终端复现脏读与幻读

事务章节是「入门到高级」的分水岭。光看 PDF 概念会觉得「可重复读」「幻读」很抽象,其实完全可以用两个 MySQL 客户端复现。

前提准备:把事务隔离级别临时调整为 READ UNCOMMITTED:

-- 在终端 A 执行 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION; -- 终端 A 更新但不提交 UPDATE t_user SET age = 99 WHERE username = 'zhangsan'; -- 此时不要 COMMIT,立刻切到终端 B

终端 B 执行:

-- 终端 B 查询(如果隔离级别是 READ UNCOMMITTED) SELECT age FROM t_user WHERE username = 'zhangsan';

终端 B 能查到 age = 99,尽管终端 A 还没提交——这就是脏读。如果把隔离级别改成 READ COMMITTED 或 REPEATABLE READ,终端 B 只会看到旧值 23,因为事务 B 的读操作读取的是已提交的版本。这个实验最大的价值在于:让你彻底理解「事务隔离级别」不是一个概念名词,而是数据库在并发读写下对一致性做出的取舍。

再复现一个不可重复读:

-- 终端 B:在同一事务内做两次查询 START TRANSACTION; SELECT age FROM t_user WHERE username = 'zhangsan'; -- 第一次查到 23 -- 此时终端 A 执行 UPDATE 并 COMMIT SELECT age FROM t_user WHERE username = 'zhangsan'; -- 第二次查到 99

在 READ COMMITTED 级别下,终端 B 两次查询结果不同,这就是不可重复读;换成 REPEATABLE READ(MySQL 默认)后,第二次查询结果仍是 23,因为事务启动时生成了读视图,后续读都基于该视图。执行这一组对比实验,你对事务章节的理解会超过看十篇笔记。

提示:复现时注意把两个客户端的 autocommit 关闭(SET autocommit = 0;),否则每个 SELECT 都会自动开启并提交一个隐式事务,看不到预期效果。

5.4 主从复制的最小配置实验

主从复制是 PDF 笔记后半程最重要的实操章节。最小配置需要两台 MySQL 实例,如果你只有一台机器,可以用 Docker 起两个容器来模拟。下面用传统 binlog + position 复制的方案给你一份可复现步骤。

主库配置(my.cnf):

[mysqld] server-id = 1 log-bin = mysql-bin binlog_format = ROW

从库配置(my.cnf):

[mysqld] server-id = 2 relay-log = relay-log read_only = ON

配置完成后重启两台 MySQL,在主库上创建复制账号并查看 binlog 坐标:

-- 主库执行 CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_password'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; SHOW MASTER STATUS;

在从库上执行 CHANGE MASTER 并启动复制:

CHANGE MASTER TO MASTER_HOST = '主库IP', MASTER_PORT = 3306, MASTER_USER = 'repl', MASTER_PASSWORD = 'repl_password', MASTER_LOG_FILE = 'mysql-bin.000001', MASTER_LOG_POS = 157; START SLAVE;

然后在主库上建一张表插入数据,到从库上查询。如果查不到,按 4.5 小节的方法看 SHOW SLAVE STATUS。整个实验做完,你才算真正掌握了 PDF 笔记里「主从复制」章节的核心——它不只是一堆参数和配置命令,而是一套可以动手验证的机制。

6. 把 PDF 笔记变成自己的技能:三个收尾习惯

6.1 用「最小复现」检验笔记里的每一条 SQL

接近这份 PDF 笔记的尾声,你会发现所有高级概念——索引、事务、锁、复制——最终都要落到「你亲手执行过」才算数。我的习惯是:每读完一小节,把该节出现的所有 SQL 整理出来,建一个练习库,逐个执行,通过故意改动条件来观察结果差异。比如看到一个「联合索引最左前缀」的例子,就自己建表、建索引、跑 EXPLAIN、对比 type 字段。这套流程不需要很久,每条 SQL 一两分钟,但效果远胜于在 PDF 上画高亮。所谓从入门到高级,其实就是一个复杂的知识网络被拆成几百个「最小复现实验」再逐个击破的过程。

6.2 给笔记做「版本化批注」

我发现所有 PDF 笔记都有一个共性问题:基于某个特定 MySQL 版本写的,但数据库技术在快速变化。比如 MySQL 8.0 的窗口函数、CTE、CHECK 约束增强,以及 8.4 移除 mysql_native_password,这些在老笔记里基本没有。所以当你在自己的环境中执行某条 SQL 报错时,先在笔记页边批注「8.0 下语法已变更」或「此写法在 5.7 没问题、8.4 将废弃」,把这些差异点沉淀下来。这比重复收藏新 PDF 高效得多——你在批注过程中建立了自己的排错知识库,这是任何现成笔记都给不了你的。

6.3 回归工作场景:从 PDF 到慢查询日志与性能调优

最后一章应该有一个收口动作:把笔记里的性能调优章节与现实工作打通。你现在可以去看本机 MySQL 的慢查询日志配置:

-- 开启慢查询日志并设置阈值 SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1; -- 确认参数生效 SHOW VARIABLES LIKE 'slow_query%'; SHOW VARIABLES LIKE 'long_query_time';

然后故意执行一条SELECT * FROM t_order CROSS JOIN t_order t2;这种笛卡尔积查询,过一会儿在日志文件里找到这条记录。看到慢查询日志真实记录下你的「坏 SQL」,比任何调优文章都更有冲击力。基于慢查询日志做索引设计,配合 EXPLAIN 验证执行计划,才是针对 MySQL 性能调优的正循环。

我的建议是,这份 PDF 笔记读完以后不要急着删,也不要急着收藏下一份。把它当作你的 MySQL 学习手册,每次在工作中遇到一个数据库问题,就先翻笔记找到对应章节,然后尝试用本地环境复现问题并解决。这个方法陪我走过从初学 SQL 语法到处理线上主从复制故障的全部阶段。笔记是死的,你是活的;只有当你把里面的每一条命令都变成自己的排错手段,「入门到高级」才算真正完成。希望这篇基于实战视角的梳理能帮你少走一些弯路,也祝你早日把那份吃灰的 PDF 变成你的 MySQL 技能地图。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进