MySQL 进阶学习笔记
本篇为《MySQL 基础知识》的进阶续篇,覆盖基础语法之后的核心主题:存储引擎、索引、SQL 性能分析、优化技巧、多表设计范式、视图、存储过程与触发器、事务底层(锁与 MVCC)、三大日志、备份恢复与运维常识。所有语法基于 MySQL 8.0(兼容 5.7 的差异均已标注)。
1. 存储引擎
1.1 查看与指定
sql
SHOW ENGINES; -- 查看所有引擎及支持情况
SELECT @@default_storage_engine; -- 查看默认引擎(8.0 默认 InnoDB)
SHOW TABLE STATUS WHERE Name = '表名'\G -- 查看某表使用的引擎
CREATE TABLE t (...) ENGINE=MyISAM; -- 建表时指定引擎
ALTER TABLE t ENGINE=InnoDB; -- 修改表引擎
1.2 InnoDB vs MyISAM 对比(高频面试)
| 对比项 | InnoDB | MyISAM |
|---|---|---|
| 事务 | 支持(ACID) | 不支持 |
| 锁粒度 | 行锁 + 表锁 | 仅表锁 |
| 外键 | 支持 | 不支持 |
| 崩溃恢复 | 靠 redo log,不易丢数据 | 容易损坏,需修复 |
| 全文索引 | 5.6+ 支持 | 支持 |
| 聚簇存储 | 是(数据随主键 B+ 树存放) | 否(数据与索引分离) |
| count(*) | 需扫描(InnoDB 8.0 优化后仍非 O(1) 精确) | 维护计数器,无 WHERE 时 O(1) |
| 适用场景 | 绝大多数 OLTP 场景(默认选择) | 只读/缓存型表、极老版本兼容 |
结论:没有特殊理由一律用 InnoDB。MEMORY(堆表)引擎可用于临时缓存,重启即失。
2. SQL 性能与架构分析
2.1 查看 SQL 执行效率的常用手段
| 手段 | 说明 |
|---|---|
SHOW STATUS |
查看服务器状态信息(如慢查询次数 Slow_queries) |
SHOW PROCESSLIST |
查看当前所有连接及其正在执行的语句(排查长事务、锁等待) |
| 慢查询日志 slow log | 记录执行时间超过阈值(long_query_time,默认 10s)的语句 |
EXPLAIN / DESCRIBE |
查看 SQL 执行计划(最重要) |
| SHOW PROFILE | 语句各阶段耗时剖析(5.6 后由 performance_schema 替代) |
| sys 库 | MySQL 5.7+ 提供的运维视图集合(如 sys.session、sys.statement_analysis) |
2.2 开启与使用慢查询日志
sql
SHOW VARIABLES LIKE 'slow_query%'; -- 是否开启、日志路径
SHOW VARIABLES LIKE 'long_query_time'; -- 阈值(秒,可为小数)
SET GLOBAL slow_query_log = ON; -- 动态开启(重启失效)
SET GLOBAL long_query_time = 1; -- 阈值设为 1 秒
持久化写入配置文件 my.cnf(Windows 为 my.ini):
ini
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1 -- 可选:未用索引的语句也记录
分析工具:mysqldumpslow slow.log 或第三方 pt-query-digest,可按耗时排序找出 Top SQL。
2.3 EXPLAIN 执行计划(重点)
把 EXPLAIN 加在 SELECT 前即可:
sql
EXPLAIN SELECT * FROM employee WHERE name = '张三';
关键输出字段:
| 字段 | 含义 |
|---|---|
| id | 执行顺序标识:id 越大越先执行;id 相同自上而下执行。子查询/UNION 会体现在 id 上 |
| select_type | 查询类型:SIMPLE(普通)、PRIMARY(最外层)、SUBQUERY(子查询)、DERIVED(FROM 中的派生表)、UNION、DEPENDENT UNION 等 |
| table | 访问的表(含派生表别名) |
| type | 访问类型(见下表,性能排序的核心指标) |
| possible_keys | 可能用到的索引 |
| key | 实际使用的索引,NULL 表示未走索引 |
| key_len | 使用的索引长度(判断联合索引被用了几列) |
| ref | 索引匹配到了哪一列/哪个常量 |
| rows | 预估要扫描的行数(越小越好) |
| filtered | 按条件过滤后剩余行的百分比(越大越好) |
| Extra | 附加信息(最容易被忽略也最有价值) |
type 访问类型(从上到下性能由好到差):
| type | 说明 | 评价 |
|---|---|---|
| system/const | 主键/唯一索引等值命中常量,最多一行 | 最好 |
| eq_ref | 连接时按主键/唯一键匹配(联表常见) | 优 |
| ref | 非唯一索引等值匹配 | 良 |
| range | 索引范围扫描(BETWEEN、>、IN) | 可接受 |
| index | 全索引树扫描(通常只为排序) | 差 |
| ALL | 全表扫描 | 最差,必须优化 |
生产要求:至少达到 range 级别,联表最好达到 ref,杜绝大表 ALL。
Extra 常见值解读:
| Extra | 含义 | 应对 |
|---|---|---|
| using filesort | 无法用索引完成排序,额外排序 | 建合适的索引让 order by 有序 |
| using temporary | 使用了临时表(常见于 group by) | 优化分组/排序索引 |
| using index | 覆盖索引,无需回表 | 理想状态 |
| using index condition | 索引条件下推 ICP,减少回表 | 良好 |
| using join buffer | 连接无索引,用缓冲优化 | 给连接列加索引 |
| Impossible where / Select tables optimized away | 条件恒假 / MAX 等被优化 | 视情况 |
2.4 分页深翻问题
sql
EXPLAIN SELECT * FROM t LIMIT 5000000, 10; -- rows 巨大:先扫 500 万行再丢弃
优化:先用覆盖索引取主键,再连接回表------
sql
SELECT a.* FROM t a
JOIN (SELECT id FROM t ORDER BY id LIMIT 5000000, 10) b ON a.id = b.id;
3. 索引(Index)
3.1 价值与代价
- 价值:类似图书目录,把全表扫描(O(n))降为索引树查找(O(log n)),大幅减少扫描行数、随机 IO 与排序开销。
- 代价:索引是额外文件(通常占数据 10%~20%+),降低增删改速度,不当使用反而更慢;所以不是所有表都必须要索引,中小数据量收益不明显。
3.2 使用原则
适合建索引:主键自动建索引;作为 WHERE/ORDER BY/GROUP BY/JOIN 条件且区分度高的列(经验值:COUNT(DISTINCT col)/COUNT(*) > 0.1);需要覆盖查询的列。
不适合:列极少(如性别)、频繁更新的列、大文本/二进制列、WHERE 从不用的列。
3.3 MySQL 8.0 支持的索引类型
| 类型 | 说明 |
|---|---|
| MAIN KEY(PRIMARY) | 唯一且非空,一表仅一个,聚簇索引 |
| UNIQUE | 唯一索引,允许 NULL |
| INDEX / NORMAL | 普通单列索引 |
| FULLTEXT | 全文索引(分词检索,InnoDB/MyISAM 均支持) |
| 前缀索引 | 对字符串列前 N 个字符建索引,节省空间 |
| 联合(多列)索引 | (a,b,c) 一树多用,遵循最左前缀 |
| 空间索引 SPATIAL | 地理数据类型 |
3.4 语法
sql
-- 建表时指定
CREATE TABLE t (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT,
INDEX idx_age_name (age, name) -- 联合索引
);
-- 单独创建
CREATE INDEX idx_name ON t(name);
ALTER TABLE t ADD INDEX idx_job_status (job, status);
-- 查看
SHOW INDEX FROM t;
-- 删除
DROP INDEX idx_name ON t;
ALTER TABLE t DROP INDEX idx_job_status;
3.5 聚簇索引与二级索引(必考)
- 聚簇索引 :InnoDB 表按主键组织,B+ 树叶子节点直接存放整行数据------找到主键即找到数据。无主键时选第一个非空唯一索引,再没有则隐藏 row id。
- 二级索引(辅助索引) :叶子节点存的是索引列值 + 主键值 。通过二级索引查到主键后,还要再走一遍聚簇索引取整行,即回表。
- 覆盖索引 :查询列全部包含在所用索引内,无需回表(Extra 显示
using index)。这是"只查必要列、避免 SELECT *"的底层原因,也是索引优化的重要目标。
3.6 最左前缀法则与失效场景(必考)
联合索引 (a, b, c) 按 a→b→c 排序建树:查询从最左列开始、不跳过中间列才能命中;WHERE b=? AND c=?(缺 a)用不上;WHERE a=? AND c=? 只能用到 a 一段(8.0 索引跳跃扫描可部分缓解)。范围条件之后的列不再参与有序匹配:a=? AND b>? AND c=? 只用 (a,b),c 靠 ICP/过滤。
索引失效的典型场景:
- 在索引列上做运算/函数 :
WHERE YEAR(dt)=2026、WHERE id+1=5(改成范围或等值原列)。 - 隐式类型转换 :字符串列用数字比较
WHERE varchar_col = 123(MySQL 把列转数字,索引失效;写= '123'即好)。 LIKE以 % 开头 :'%abc';'abc%'、'a%c'仍可用。OR连接的条件中有未建索引的列(整体退化为全表扫描)。NOT IN、!=、<>、IS NOT NULL等:优化器认为无索引可用时会放弃(数据分布决定,不是绝对失效)。- 未满足最左前缀(如上)。
- 优化器判断全表扫描更快(如命中比例过高、表很小)。
3.7 前缀索引与 EXPLAIN 验证
sql
ALTER TABLE t ADD INDEX idx_email (email(12)); -- 取前 12 个字符
-- 用区分度选前缀长度:
SELECT COUNT(DISTINCT LEFT(email,12))/COUNT(*) FROM t;
每加一个索引都要用 EXPLAIN 验证效果;加完索引发现没提速,多半是写法触发了失效场景。
4. SQL 优化技巧
4.1 插入与批量
- 批量插入一条 SQL 多组 VALUES,或
LOAD DATA INFILE(最快)。 - 导入前先关二级索引、
DISABLE KEYS,导入后重建。 - 主键尽量自增顺序插入,减少 B+ 树页分裂。
4.2 查询书写
- 只查需要的列 ,不滥用
SELECT *(减少 IO、便于覆盖索引)。 - WHERE 中把区分度高的条件放前面(对优化器影响有限,但写法好习惯)。
- 用
EXISTS替代IN处理大子查询、用IN替代大量OR(视数据量,用 EXPLAIN 验证)。 - 避免在 WHERE 中对列运算,把计算挪到常量侧:
WHERE dt >= '2026-01-01'而非WHERE DATE(dt)=...。 ORDER BY尽量与索引顺序一致;GROUP BY会隐式排序,8.0 已移除GROUP BY ... ORDER BY NULL,需要无序时用ORDER BY NULL替代写法或评估排序成本。- 分页用"延迟关联"(见 2.4)。
JOIN用小表驱动大表(MySQL 的 NLJ 本质如此,写 STRAIGHT_JOIN 前先测);确保连接列有索引。
4.3 结构与配置
- 大表做垂直拆分 (冷热字段分表)与水平分库分表;单表经验阈值 500 万~2000 万行。
- 合理冗余(反范式)减少联表。
- 连接数
max_connections、缓冲池innodb_buffer_pool_size(物理内存 50%~70%)等参数按需调整。 - 读写分离、引入缓存(Redis)分流热点读。
5. 数据设计与多表关系
5.1 三大范式(设计基线)
- 第一范式 1NF:字段原子性,不可再分(地址拆成省/市/街道/邮编)。
- 第二范式 2NF :消除对主键的部分依赖------联合主键下,非主键列必须依赖整个主键,否则拆表。
- 第三范式 3NF :消除传递依赖------非主键列不能依赖另一个非主键列(学生表里不放"学院电话")。
实际开发:先满足 3NF;为性能可反范式冗余,用空间换时间,配合一致性逻辑。
5.2 多表关系建模
| 关系 | 建法 |
|---|---|
| 一对一 1:1 | 外键放任意一侧(常拆热点/冷点字段,如用户与详情表) |
| 一对多 1:N | 外键放"多"的一方(部门→员工) |
| 多对多 N:N | 建中间表,存双方主键两个外键 |
6. 视图(View)
6.1 概念与价值
视图是虚拟表,只存查询定义不存数据(物化视图 MySQL 原生不支持)。价值:简化复杂查询、屏蔽表结构细节(表改名改列时业务 SQL 不变)、聚焦行列级权限安全。注意:视图本身不提升性能,底层仍是原查询。
6.2 语法
sql
CREATE [OR REPLACE] VIEW v_emp_dept AS
SELECT e.name, d.dept_name FROM employee e JOIN dept d ON e.dept_id = d.id;
SHOW CREATE VIEW v_emp_dept; -- 查看定义
DESC v_emp_dept; -- 查看结构
DROP VIEW [IF EXISTS] v_emp_dept;
SELECT * FROM v_emp_dept WHERE dept_name = '研发部'; -- 像表一样查
更新基表数据,视图结果随之变化(视图无独立数据)。
6.3 可更新性与 WITH CHECK OPTION
单表视图的增删改会作用到基表;含 DISTINCT、GROUP BY、聚合、JOIN 等的视图不可更新。
sql
CREATE OR REPLACE VIEW v_dept_emp AS
SELECT * FROM employee WHERE dept_id = 1
WITH CHECK OPTION; -- 通过视图插入/更新时,必须仍满足 dept_id=1,否则报错
LOCAL CHECK(默认)只校验本视图条件;CASCADED CHECK 连上游视图条件一起校验。
7. 编程能力:变量、流程、游标
7.1 变量
sql
-- 系统变量
SELECT @@global.autocommit; -- 全局
SELECT @@session.tx_isolation; -- 会话(@@ 前省略即 session)
SET SESSION sort_buffer_size = 4194304; -- 修改会话变量
-- 用户变量(@ 开头,当前会话有效,set 任意语句中)
SET @a = 10, @b = 20;
SELECT @sum := @a + @b;
SELECT name FROM t LIMIT @offset, 10; -- 典型:分页变量
-- 局部变量(存储过程/函数内 DECLARE,必须在 BEGIN 块开头声明)
DECLARE total INT DEFAULT 0;
SET total = 1;
SELECT COUNT(*) INTO total FROM employee; -- INTO 赋值
7.2 流程控制
sql
-- IF(存储过程内)
IF score >= 90 THEN SET @g = 'A';
ELSEIF score >= 60 THEN SET @g = 'B';
ELSE SET @g = 'C';
END IF;
-- CASE
SELECT name,
CASE WHEN job = 'Manager' THEN salary * 2
WHEN job = 'Salesman' THEN salary * 1.5
ELSE salary END AS new_sal
FROM emp;
SELECT *, CASE job WHEN 'CLERK' THEN '文员' WHEN 'MANAGER' THEN '经理' ELSE job END FROM emp;
-- LOOP / LEAVE(相当于 break)
DECLARE i INT DEFAULT 1;
lbl: LOOP
SET i = i + 1;
IF i > 10 THEN LEAVE lbl; END IF;
END LOOP lbl;
-- WHILE / DO...WHILE / REPEAT...UNTIL
WHILE i <= 10 DO SET i = i + 1; END WHILE;
REPEAT SET i = i + 1; UNTIL i > 10 END REPEAT;
7.3 游标(Cursor)
对 SELECT 结果集逐行处理(本质是"结果集上的指针"):
sql
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR SELECT name FROM employee;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- 取不到数据时置标志
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_name;
IF done THEN LEAVE read_loop; END IF;
-- 逐行处理 v_name ...
END LOOP;
CLOSE cur;
游标只能用在存储过程/函数中;大结果集慎用,性能差,能用集合化 SQL 就不要逐行。
8. 存储过程与存储函数
8.1 概念对比
| 存储过程 PROCEDURE | 存储函数 FUNCTION | |
|---|---|---|
| 返回值 | 无(可用 OUT 参数带出) | 必须有且仅有一个 RETURN |
| 调用 | CALL p() |
嵌入 SQL:SELECT f(x) |
| 典型用途 | 复杂业务流程(批量、报表) | 计算并返回单值 |
价值:一次编译长期复用(提升速度)、降低网络往返、封装权限(用户可执行而无需表权限)、可移植。缺点:调试难、版本管理弱、业务逻辑散落库中,互联网实践中常放应用层。
8.2 语法要点(DELIMITER 必知)
sql
DELIMITER $$ -- 改语句结束符,避免过程内分号提前截断
CREATE PROCEDURE p_sal(
IN emp_id INT, -- IN 入参;OUT 出参;INOUT 双向
OUT avg_sal DECIMAL(10,2))
BEGIN
SELECT AVG(salary) INTO avg_sal FROM employee WHERE dept_id = emp_id;
END$$
DELIMITER ;
CALL p_sal(1, @s);
SELECT @s;
CREATE FUNCTION f_year_bonuses(base INT) RETURNS INT
DETERMINISTIC -- 函数必须声明特性,否则 binlog 开启时报错
BEGIN
DECLARE i INT DEFAULT 1; DECLARE total INT DEFAULT 0;
WHILE i <= 3 DO
SET total = total + base; SET i = i + 1;
END WHILE;
RETURN total;
END$$
SELECT f_year_bonuses(5000);
管理语句:
sql
SHOW PROCEDURE STATUS; -- 列出所有过程(Db/Name)
SHOW CREATE PROCEDURE p_sal; -- 查看定义
DROP PROCEDURE [IF EXISTS] p_sal; -- DROP FUNCTION 同理
权限不足时检查 log_bin_trust_function_creators(开 binlog 时创建函数需要 SUPER 或该参数置 1)。
9. 触发器(Trigger)
9.1 概念与组成
基于事件 + 时机自动执行的 SQL 集合:事件 = INSERT/UPDATE/DELETE;时机 = BEFORE/AFTER;粒度 = FOR EACH ROW 行级(MySQL 仅支持行级)。典型用途:审计日志、强制复杂约束、自动衍生值维护。
sql
DELIMITER $$
CREATE TRIGGER trg_emp_before_ins
BEFORE INSERT ON employee -- 时机 + 事件 + 表
FOR EACH ROW
BEGIN
IF NEW.salary < 0 THEN SET NEW.salary = 0; END IF;
SET NEW.created_by = CURRENT_USER();
END$$
DELIMITER ;
NEW:新行(INSERT/UPDATE 后的值;UPDATE 中可改 NEW 实现数据修正)。OLD:旧行(DELETE/UPDATE 前的值,INSERT 时不可用)。- BEFORE 校验/改写数据;AFTER 记录、联动(如写入审计表)。
9.2 管理
sql
SHOW TRIGGERS; -- 可 LIKE '表名' / FROM 库名 过滤
DROP TRIGGER IF EXISTS trg_emp_before_ins;
⚠️ 坑:触发器里不能再操作触发它的那张表 (自引用限制,报错 "Can't update table ... in function call"),需要绕行应用层或函数封装;触发器隐蔽性强,团队协作中建议在文档/命名上明确(如 tri_表_时机_事件)。
10. 事务底层:锁与隔离
10.1 并发事务三大问题回顾
脏读(读到未提交)、不可重复读(同行两次读不同,因 UPDATE)、幻读(两次查询行数不同,因 INSERT)。隔离级别由低到高:READ UNCOMMITTED / READ COMMITTED / REPEATABLE READ(MySQL 默认) / SERIALIZABLE,级别越高越安全、并发越差。
10.2 锁的分类
| 维度 | 类型 |
|---|---|
| 粒度 | 全局锁(FTWRL,全库只读做逻辑备份)、表级锁、行级锁 |
| 模式 | 共享锁 S(读)、排他锁 X(写);SELECT ... LOCK IN SHARE MODE / FOR SHARE、FOR UPDATE |
| 姿态 | 乐观锁(版本字段 CAS,应用层思想)、悲观锁(FOR UPDATE) |
| 意图 | 意向锁 IS/IX:表级"占位声明",加速表锁判断 |
表级锁细节 :表锁(阻塞增删改查)、LOCK TABLES ... READ/WRITE 显式锁、元数据锁 MDL(DML 持 MDL 读、DDL 持 MDL 写------DDL 卡在长事务前多为 MDL 等待)、自动锁定(配合 INSERT ... AUTO_INCREMENT)。
InnoDB 行锁三种算法(RR 级别下):
- Record Lock:锁具体记录行。
- Gap Lock:锁记录间空隙,只阻止插入、不互斥,解决幻读。
- Next-Key Lock:Record + Gap(左开右闭区间),InnoDB 默认加锁单位。
⚠️ 行锁只对索引生效 :不加索引条件或优化器放弃索引时,升级为锁扫描到的所有行/间隙,近似表锁。死锁:两个事务互相等待,innodb_deadlock_detect 会回滚代价小的一方(错误码 1213),业务需重试。
10.3 MVCC 多版本并发控制(RR 的核心)
- 目标:读写不互相阻塞------读快照不加锁,写当前版本加锁。
- 三要素:
- 隐藏字段:每行带事务 ID(trx_id)与回滚指针(roll_pointer)。
- undo log 版本链:修改前旧值沿链保存,形成历史版本。
- ReadView 读视图:记录快照时刻的活跃事务列表(m_ids)、min/max_trx_id、创建者 id。读取时沿版本链找"对自己可见"的版本。
- 可见性判断要点:trx_id = 创建者 → 可见;不在 m_ids(已提交)→ 可见;≥ max_trx_id(快照后才开启)→ 可见;在 m_ids 内 → 不可见,沿链上溯。
- RC 与 RR 的本质区别:RC 每次 SELECT 生成新 ReadView(会读到别的事务已提交的新值→不可重复读);RR 只在事务第一次 SELECT 生成一次(全程同一快照→可重复读)。
- MVCC 解决"快照读"(普通 SELECT)的不可重复读与大部分幻读;"当前读"(FOR UPDATE、UPDATE、SELECT 走锁)由 Next-Key Lock 解决。
10.4 长事务危害
undo log 膨胀版本链变长、锁持有时间长、连接与 ID 资源耗尽。上线前用 SELECT * FROM information_schema.innodb_trx WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60; 抓长事务。
11. MySQL 日志体系
| 日志 | 层 | 作用 |
|---|---|---|
| 错误日志 error log | server | 启动/运行报错,排障第一入口 |
| 慢查询日志 slow log | server | 性能分析(见第 2 章) |
| 二进制日志 binlog | server | 归档型 :记录所有变更 DDL/DML 的语句(不记录 SELECT),用于主从复制 与数据恢复(任意时间点) |
| 回滚日志 undo log | InnoDB | 回滚型:保存旧版本,构成 MVCC 版本链、支撑事务回滚 |
| 重做日志 redo log | InnoDB | 环形物理日志:记录页的修改,保证崩溃后数据不丢(WAL) |
两阶段提交(2PC):更新时先写 redo log(prepare)→ 写 binlog → 提交 redo log(commit)。为什么需要:保证 redo(实例恢复)与 binlog(归档/主从)两份日志逻辑一致------宕机恢复后主从不因" redo 有 binlog 无"而数据分叉。
刷盘策略 innodb_flush_log_at_trx_commit:1 最安全(每次提交刷盘),2 性能较好且宕 OS 不丢,0 仅每秒刷。binlog 刷盘 sync_binlog 同理,双 1 为金融级配置。
12. 备份与恢复
12.1 分类
- 物理备份:直接拷数据文件(冷备需停服;热备用 Percona XtraBackup)。
- 逻辑备份:导出 SQL 语句(mysqldump),可跨版本、可细粒度挑选。
- 全量 / 增量;冷 / 热 / 温;恢复目标:整库、指定表、任意时间点(binlog 重放)。
12.2 mysqldump 常用
bash
mysqldump -u root -p db_name > db.sql # 备份单库
mysqldump -u root -p --all-databases > all.sql # 所有库(-B 指定多库)
mysqldump -u root -p db_name tbl1 tbl2 > t.sql # 指定表(-T 可导出为数据文件+建表)
mysqldump -u root -p --single-transaction --master-data=2 db > db.sql # InnoDB 一致性热备 + 记录 binlog 位点(主从/时间点恢复用)
mysql -u root -p db_name < db.sql # 恢复
备份策略口诀:定期全备 + 持续 binlog ,恢复 = 最近全备 + 重放其后 binlog。逻辑备份适合中小库;大库用物理热备工具,并务必演练恢复(没验证过的备份等于没有备份)。
13. 附录:配置管理与常见报错
13.1 配置文件与优先级
- Linux:
/etc/my.cnf(全局)、~/.my.cnf;Windows:my.ini。 - 优先级:
mysqld --参数>mysqld_safe --参数>etc/my.cnf>login shell。 - 关键参数:
datadir、port、max_connections、innodb_buffer_pool_size、character-set-server=utf8mb4、大小写敏感lower_case_table_names(Linux 默认区分,建库前定好)。
13.2 高频报错速查
| 报错 | 原因与处理 |
|---|---|
| 1062 Duplicate entry | 唯一/主键冲突 |
| 1213 Deadlock found | 死锁,业务重试;缩短事务、统一加锁顺序 |
| 1205 Lock wait timeout | 锁等待超时,查 innodb_trx / processlist 找持锁方 |
| 1242 Subquery returns more than 1 row | 标量子查询返回多行,改 IN 或加 LIMIT |
| ERROR 2002/10061 无法连接 | 服务未启动 / 端口 / bind-address 配置 |
| 外键报错 150/1452 | 引用列非主键唯一,或从表数据违反约束 |
| 函数创建报 binlog 错误 | SET GLOBAL log_bin_trust_function_creators = 1 或补特性声明 |
13.3 进阶方向
- 高可用:主从复制原理(binlog→relay log→SQL 线程)、GTID、MHA/InnoDB Cluster、读写分离中间件
- 分库分表:水平拆分路由(ShardingSphere)、全局 ID(雪花算法)
- 新特性:窗口函数(8.0
OVER())、CTE(WITH)、JSON 类型与函数、直方图、不可见索引、DESC 索引、information_schema/performance_schema深度使用 - 内核向:B+ 树页结构、Change Buffer、Doublewrite、自适应哈希