关注

MySQL 2026长效实战教程:从零基础入门到大厂生产架构落地

MySQL 2026长效实战教程:从零基础入门到大厂生产架构落地

摘要

本文是一份面向2026年技术生态的 MySQL 8.0 LTS 全栈实战教程,覆盖从零基础入门到大厂生产架构落地的完整学习路径。全文共分四大模块:模块一系统讲解SQL基础语法、三大范式、数据类型选型、DDL/DML/DQL及SQL反模式避坑;模块二深入剖析MySQL 8.0核心新特性,包括窗口函数、CTE、JSON操作、Hash Join、Instant DDL、自增值持久化等;模块三聚焦生产环境必备技能,涵盖B+树原理、索引优化体系(ICP/MRR/直方图/EXPLAIN ANALYZE)、事务隔离级别、间隙锁与死锁实战、SKIP LOCKED高并发方案、Binlog体系及分区表设计;模块四提供运维架构方案(主从复制、分库分表、压测监控)及40+大厂高频面试题库。

版本说明:本文基于 MySQL 8.0 LTS(2026年生产主流),兼容5.7旧项目维护。所有示例均使用统一的电商数据库(用户、订单、商品、分类、评论)。

🧩 快速导航

  • [基础] 语法/DDL/范式 → 模块1
  • [新特性] 窗口函数/直方图/Instant DDL → 模块2
  • [调优] 执行计划/索引失效/SQL改写 → 模块3
  • [面试] 40+高频场景题 → 模块4

👨‍🎓 阅读分层指引

  • 🟢 学生/零基础:模块1(基础语法+范式+数据类型+DDL/DML/DQL)
  • 🟡 初级后端:模块1 + 模块2(8.0新特性)+ 模块3(索引+事务+锁+规范)
  • 🔴 面试/进阶:全部四个模块,重点掌握模块3底层原理和模块4面试题库

📌 全文约定

  • 生产推荐:2026年项目标准写法
  • ⚠️ 坑点:新手极易出错、线上故障场景
  • 📌 面试考点:校招/社招高频考题
  • 🔧 8.0专属:5.7不兼容特性

文章目录


模块0:前置导读

0.1 MySQL版本选型

版本状态推荐度
MySQL 8.0 LTS2026生产主流⭐⭐⭐⭐⭐
MySQL 5.7已停止维护,仅遗留项目⭐⭐
MyISAM引擎已淘汰,新项目禁用

核心变化

  • 字符集默认 utf8mb4(支持emoji)
  • 密码插件 caching_sha2_password
  • 原子DDL、隐藏索引、窗口函数、Hash Join、Instant DDL
  • 自增值持久化(存于数据字典表mysql.auto_increment_counter,重启不丢失)
  • 废弃password()函数、utf8(3字节)、老式分区语法

0.2 全文约定

  • 生产推荐:2026年项目标准写法
  • ⚠️ 坑点:新手极易出错、线上故障场景
  • 📌 面试考点:校招/社招高频考题
  • 🔧 8.0专属:5.7不兼容特性

0.3 阅读分层指引

  • 学生/零基础:模块1(基础语法+范式+数据类型+DDL/DML/DQL)
  • 初级后端:模块1 + 模块2(8.0新特性)+ 模块3(索引+事务+锁+规范)
  • 面试/进阶:全部四个模块,重点掌握模块3底层原理和模块4面试题库

模块1:MySQL零基础核心

1.1 SQL概述与四大语言

-- DDL: 数据定义语言
CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- DML: 数据操纵语言
INSERT INTO user(name) VALUES('张三');

-- DQL: 数据查询语言
SELECT * FROM user WHERE id = 1;

-- DCL: 数据控制语言
GRANT SELECT ON shop.* TO 'reader'@'%';

1.2 三大范式与反范式设计

  • 第一范式:每列不可再分
  • 第二范式:非主键列完全依赖于主键
  • 第三范式:非主键列不传递依赖
  • 反范式(生产常用):在订单表中冗余商品名称、价格,避免每次查询都JOIN商品表,提升读性能。
    CREATE TABLE `order` (
      id BIGINT UNSIGNED AUTO_INCREMENT,
      product_name VARCHAR(100) NOT NULL DEFAULT '', -- 冗余字段
      product_price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
      ...
    );
    

1.3 数据类型(2026标准)

类型推荐用法避坑
INT / BIGINT主键用 BIGINT UNSIGNED AUTO_INCREMENT不要用INT做主键,可能溢出
DECIMAL(M,D)金额专用,如 DECIMAL(10,2)禁止FLOAT/DOUBLE
VARCHAR(N)变长字符串,N为字符数8.0中VARCHAR(255)以内一个字符占1~4字节
CHAR(N)定长字符串,适合固定长度编码如手机号 CHAR(11)
DATETIME推荐存储时间,范围’1000-01-01’到’9999-12-31’避免TIMESTAMP(2038年问题)
JSON8.0原生支持,适合存储扩展属性代替多字段冗余设计
TEXT/BLOB大文本/二进制,建议单独分表存储不在主表中存放

⚠️ 坑点:禁止使用TIMESTAMP,因为2038年溢出;禁止使用utf8(3字节),必须用utf8mb4

1.4 库与表DDL操作

-- 建库
CREATE DATABASE shop 
  DEFAULT CHARACTER SET utf8mb4 
  COLLATE utf8mb4_unicode_ci;

-- 建表(强制指定引擎和字符集)
CREATE TABLE user (
  id       BIGINT UNSIGNED AUTO_INCREMENT COMMENT '用户ID',
  name     VARCHAR(50) NOT NULL DEFAULT '' COMMENT '用户名',
  phone    CHAR(11) NOT NULL DEFAULT '' COMMENT '手机号',
  create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (id),
  UNIQUE KEY uk_phone (phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

⚠️ 坑点:线上禁止无WHERE的UPDATE/DELETE,务必先SELECT确认范围。

1.5 五大约束(含生产建议)

约束说明生产建议
PRIMARY KEY主键,唯一标识一行推荐自增BIGINT UNSIGNED
FOREIGN KEY物理外键⚠️ 分布式/微服务架构坚决禁用;单库小型后台管理(如内部OA)可根据团队规范酌情使用。现代架构推荐逻辑外键(业务代码保证)
UNIQUE唯一约束用于手机号、身份证等业务唯一字段
NOT NULL非空尽量设置NOT NULL + DEFAULT值,减少索引开销
CHECK检查约束8.0完整支持,可用于简单校验(如年龄>0)

1.6 DML增删改查

-- 批量插入(推荐)
INSERT INTO user(name, phone) VALUES 
('张三','13800138000'),
('李四','13900139000');

-- 存在则更新(ON DUPLICATE KEY UPDATE)
INSERT INTO user(id, name) VALUES(1,'王五')
ON DUPLICATE KEY UPDATE name=VALUES(name);

-- 安全删除(分批避免长事务)
DELETE FROM order_log WHERE id < 1000 LIMIT 500;
-- 循环执行直到影响行数为0

-- TRUNCATE vs DELETE
-- DELETE可回滚,TRUNCATE不可回滚(重置自增ID),注意8.0下TRUNCATE受外键约束限制

1.7 DQL查询进阶

-- COUNT(*)  vs COUNT(1) vs COUNT(字段)
-- COUNT(*) 统计行数最快,包含NULL;COUNT(字段)忽略NULL

-- 大分页优化(延迟关联 / 覆盖索引回表)
-- 坏写法:SELECT * FROM order LIMIT 100000, 20;
-- 好写法(通用无漏洞,支持任意跳页):
SELECT * FROM order t1 
JOIN (SELECT id FROM order ORDER BY id LIMIT 100000, 20) t2 
ON t1.id = t2.id;

-- 游标分页(仅适用于上一页/下一页,不适用于跳页,否则会漏行)
SELECT * FROM order WHERE id > 100000 ORDER BY id LIMIT 20;

-- GROUP BY 严格模式(8.0默认ONLY_FULL_GROUP_BY)
-- 解决办法:SELECT的列必须在GROUP BY中或使用聚合函数

1.8 多表连接与子查询

-- JOIN优化:小表驱动大表,关联字段建索引
SELECT u.name, o.order_no
FROM user u
INNER JOIN `order` o ON u.id = o.user_id
WHERE u.create_time > '2026-01-01';

-- 子查询嵌套不超过3层,推荐用CTE替代

1.9 常见SQL反模式自查表

错误写法(❌)正确写法(✅)原因
SELECT * FROM order WHERE name LIKE '%张%'前端改为输入完整前缀或使用全文索引前缀模糊查询导致索引失效
WHERE status != 1改写为 WHERE status IN (0,2,3) 或利用枚举!=是否走索引由优化器基于数据分布动态决定,非绝对失效
ORDER BY RAND() LIMIT 1使用程序随机生成ID范围,或使用临时表ORDER BY RAND() 会导致全表扫描和排序
WHERE DATE(create_time) = '2026-01-01'WHERE create_time >= '2026-01-01' AND create_time < '2026-01-02'对索引列使用函数会失效
HAVING COUNT(*) > 1GROUP BY 列少先用子查询过滤,再用 HAVINGHAVING 会在分组后再过滤,效率低于 WHERE

模块2:MySQL 8.0现代核心特性

2.1 CTE公用表表达式(WITH)

-- 查询每个用户的订单总金额
WITH user_order_total AS (
  SELECT user_id, SUM(amount) total_amount
  FROM `order`
  GROUP BY user_id
)
SELECT u.name, uot.total_amount
FROM user u
LEFT JOIN user_order_total uot ON u.id = uot.user_id;

2.2 窗口函数(面试必考)

-- 按部门工资排名
SELECT 
  emp_name,
  dept_id,
  salary,
  ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rank_in_dept
FROM employee;

-- 计算月度销售额环比
SELECT 
  month,
  revenue,
  LAG(revenue,1) OVER (ORDER BY month) AS prev_month_revenue,
  (revenue - LAG(revenue,1) OVER (ORDER BY month)) / LAG(revenue,1) OVER (ORDER BY month) AS growth_rate
FROM monthly_sales;

2.3 JSON完整操作

-- 插入JSON
INSERT INTO product_extra(product_id, attrs) 
VALUES(1, JSON_OBJECT('color','red','size','M'));

-- 提取JSON字段
SELECT JSON_EXTRACT(attrs, '$.color') FROM product_extra;

-- JSON_TABLE:将JSON转为关系表
SELECT p.*, jt.color, jt.size
FROM product p,
JSON_TABLE(p.attrs, '$' COLUMNS(
  color VARCHAR(10) PATH '$.color',
  size VARCHAR(10) PATH '$.size'
)) AS jt;

2.4 索引新特性

-- 隐藏索引(测试删除效果而不真正删除)
ALTER TABLE user ALTER INDEX idx_phone INVISIBLE;
-- 观察一段时间后若不影响性能,再DROP

-- 降序索引(8.0支持)
CREATE INDEX idx_create_desc ON `order`(create_time DESC);

-- 函数索引(解决WHERE DATE(create_time)=...无法走索引)
CREATE INDEX idx_create_date ON `order`((DATE(create_time)));

2.5 安全与认证

-- 创建用户并设置密码过期时间
CREATE USER 'app_user'@'%' IDENTIFIED WITH caching_sha2_password BY 'StrongPass123!'
PASSWORD EXPIRE INTERVAL 90 DAY;

-- 密码强度策略
SET GLOBAL validate_password.policy = STRONG;

2.6 Hash Join(8.0.18+)

  • 作用:当关联字段没有索引时,自动使用Hash Join替代传统的Block Nested-Loop Join,大幅提升性能。
  • 触发条件join_buffer_size足够大,且optimizer_switchhash_join=on
  • 示例(模拟无索引关联):
-- 旧版(5.7)会使用BNL,速度慢
-- 8.0会自动使用Hash Join
SELECT /*+ HASH_JOIN(o,oi) */ o.order_no, oi.product_name
FROM `order` o
JOIN order_item oi ON o.id = oi.order_id
WHERE o.create_time > '2026-01-01';
  • 生产建议:仍应优先为关联字段建索引,Hash Join只是兜底方案。

2.7 Instant DDL(8.0.12+)

  • 作用:某些ALTER操作可以瞬间完成,不阻塞DML。
  • 支持的操作
    • ADD COLUMN(MySQL 8.0.29+ 已支持在表的任意位置(FIRST/AFTER) 添加列,无需重建表;8.0.12~8.0.28仅支持末尾追加)
    • DROP COLUMN(8.0.23+)
    • MODIFY COLUMN(仅修改默认值)
  • 查看是否instant
ALTER TABLE user ADD COLUMN age TINYINT UNSIGNED DEFAULT 0, ALGORITHM=INSTANT;

2.8 8.0其他高频新特性

2.8.1 持久化全局变量(SET PERSIST
-- 无需修改配置文件、无需重启
SET PERSIST long_query_time = 1;
2.8.2 角色管理(Role)
CREATE ROLE dev_read;
GRANT SELECT ON shop.* TO dev_read;
GRANT dev_read TO 'zhang'@'%';
2.8.3 表达式默认值
create_time DATETIME DEFAULT NOW()
2.8.4 自增ID不连续问题(面试必考)
  • 现象:删除数据、事务回滚后,自增ID不会回填,导致ID断层。
  • 5.7致命缺陷:自增值存在内存,重启数据库会重置自增值,导致复现已删除ID、主键冲突。
  • 8.0核心优化:自增值持久化到 mysql.auto_increment_counter 系统表(数据字典),重启不丢失、不回溯,彻底解决5.7重启ID错乱问题。(注意:并非存于redo log,redo log仅负责物理事务恢复)
  • 生产结论:自增ID不保证连续,只保证单调递增、唯一。业务绝对不能依赖ID连续(流水号、排序、统计)。
2.8.5 8.0彻底删除的过时特性
  1. 废弃 myisam 为默认引擎
  2. 废弃 utf8(3字节),强制 utf8mb4
  3. 废弃 password() 函数,只能用 caching_sha2_password
  4. 废弃老式分区语法
  5. ONLY_FULL_GROUP_BY 8.0强制开启(5.7可关闭)

模块3:生产环境必备

3.1 存储引擎:InnoDB深度解析

  • 聚簇索引:主键即数据,二级索引叶子节点存主键值
  • 事务ACID:通过redo log(持久性)、undo log(原子性/隔离性)实现
  • 隔离级别:默认RR(可重复读),通过MVCC + Next-Key Lock解决幻读
  • 锁机制:行锁(Record Lock)、间隙锁(Gap Lock)、临键锁(Next-Key Lock)
  • 死锁:两个事务互相等待对方释放锁,通过innodb_deadlock_detect自动检测并回滚其中一个

3.2 索引完整体系

3.2.1 B+树优势
  • 非叶子节点不存数据,可存放更多索引,降低树高
  • 叶子节点形成双向链表,支持范围查询高效
  • 相比哈希索引,支持排序和范围查询
3.2.2 联合索引最左匹配原则
CREATE INDEX idx_a_b_c ON t(a,b,c);
-- 走索引:WHERE a=1 AND b=2
-- 走索引:WHERE a=1 AND c=3 (仅用到a列)
-- 不走索引:WHERE b=2 (没有a)
3.2.3 索引失效10大场景(精选)
  1. LIKE '%xxx' 前缀模糊
  2. 对索引列使用函数 WHERE DATE(create_time)=...
  3. 隐式类型转换 WHERE phone=13800138000(phone是varchar)
  4. OR条件中有一个非索引列
  5. !=<> 操作符(是否失效由优化器基于数据分布(选择性)动态决定,非绝对失效
  6. IS NOT NULL同样取决于数据分布,若匹配数据量极少则走索引
  7. 联合索引跳过中间列
  8. 表数据量很小(优化器认为全表扫描更快)
  9. 索引列参与运算 WHERE age+1=20
  10. 使用NOT IN、NOT EXISTS(可能失效)

📌 面试口诀:函数、运算、隐转、前模糊、or断索引、不满足最左。注意后三条需结合数据分布判断。

3.2.4 索引下推(ICP)
  • 定义:在二级索引遍历时,提前过滤不符合条件的行,减少回表次数。
  • 启用SET optimizer_switch = 'index_condition_pushdown=on';(默认开启)
  • 示例
-- 联合索引 (zipcode, lastname, firstname)
SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%etrunia%';
-- 5.7:先通过zipcode找到所有记录,再回表过滤lastname
-- 8.0:在索引层面就判断lastname是否匹配,不匹配的不回表
  • EXPLAIN显示Extra列出现 Using index condition
3.2.5 MRR(Multi-Range Read)
  • 作用:将随机I/O转化为顺序I/O,适用于二级索引范围查询后需要回表的情况。
  • 原理:先将满足条件的二级索引的主键值放入缓冲区排序,然后按主键顺序回表读取数据。
  • 启用SET optimizer_switch = 'mrr=on,mrr_cost_based=off';
  • 适用场景WHERE key_part1 > 100 AND key_part1 < 200 这种范围查询,且需要回表获取整行数据。
3.2.6 覆盖索引最佳实践

避免回表 = 极致性能,Extra显示Using index

3.2.7 索引选择性概念
  • 选择性 = 去重值数量 / 总行数。选择性太低(如性别、状态)不适合建索引,MySQL优化器会直接全表扫描。
  • 建索引黄金标准:选择性 > 20% 且查询频繁的列。
3.2.8 直方图(Histograms)—— 8.0调优利器
  • 作用:当索引列数据分布极度不均(如90%为0,10%为1)时,优化器可能选错索引。直方图为优化器提供列值分布统计信息,帮助其精准估算行数。
  • 操作
-- 更新直方图(默认采样100)
ANALYZE TABLE orders UPDATE HISTOGRAM ON status, category_id;

-- 查看直方图元数据
SELECT * FROM information_schema.column_statistics WHERE table_name = 'orders';

-- 删除直方图
ANALYZE TABLE orders DROP HISTOGRAM ON status;
3.2.9 EXPLAIN执行计划解读(含EXPLAIN ANALYZE)
字段含义优秀值
type访问类型const > eq_ref > ref > range > index > ALL
key实际使用的索引不为NULL
rows预估扫描行数越小越好
Extra额外信息Using index(覆盖索引)最优

🔧 8.0专属 EXPLAIN ANALYZE(8.0.18+):

  • 作用实际执行SQL,输出每一步的真实耗时(毫秒)和循环次数,是排查"预估rows很小但实际执行极慢"的终极武器。
  • 示例
EXPLAIN ANALYZE SELECT * FROM order WHERE create_time > '2026-06-01'\G
-- 输出包含:实际执行时间 (actual time)、实际循环次数 (loops)、实际扫描行数

3.3 大厂建表规范(可直接落地)

CREATE TABLE `order` (
  `id`         BIGINT UNSIGNED AUTO_INCREMENT COMMENT '订单ID',
  `user_id`    BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
  `order_no`   VARCHAR(32) NOT NULL DEFAULT '' COMMENT '订单号',
  `total_amount` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '订单金额',
  `status`     TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '状态:0待支付1已支付2已取消',
  `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_order_no` (`order_no`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

规范要点

  • 必须有主键、注释、非空+默认值
  • 避免TEXT/BLOB在主表,拆分附属表
  • 时间统一DATETIME,不使用字符串
  • 金额用DECIMAL,不用FLOAT/DOUBLE
  • 禁止存储图片/文件,只存URL

3.4 SQL性能优化清单

  1. 禁止SELECT *,只查询需要的字段
  2. 模糊查询LIKE 'xxx%' 可走索引,LIKE '%xxx' 不可
  3. 多表JOIN:不超过3~5张,关联字段建索引
  4. 大事务拆分:单个事务执行时间控制在3秒内
  5. IN子查询:集合元素不宜超过1000,否则拆分为多个查询或用临时表
  6. OR条件:改为UNION ALL(如果两边都能走索引)

3.5 事务与锁:生产实战避坑

3.5.1 幻读的完整真相(面试90%人答错)
  • 读幻读:普通快照读(MVCC)不会幻读
  • 写幻读:当前读(UPDATE/DELETE/SELECT … FOR UPDATE)依然会幻读
  • InnoDB RR解决的是「写幻读」(通过Next-Key Lock)
3.5.2 间隙锁触发条件(生产高频死锁根源)

只有 InnoDB RR 级别才会产生间隙锁。触发场景:

  1. 条件是范围查询(> < BETWEEN)
  2. 唯一索引不命中任何数据
  3. 普通索引范围更新

避坑方案(生产必用)

  • 尽量使用精准等值查询更新
  • 小事务、短锁、后置写操作
3.5.3 死锁必现场景 + 根治方案

必现死锁:两个事务加锁顺序相反

  • T1:锁A → 等B
  • T2:锁B → 等A

根治:所有业务统一加锁顺序(ID从小到大)

3.5.4 高并发神器:SKIP LOCKEDNOWAIT(8.0)
  • SKIP LOCKED:跳过已被其他事务锁定的行,永不阻塞、永不超时。适用于任务队列 / 秒杀扣减场景。
  • NOWAIT:若遇到锁则立即报错返回,不等待。
  • 示例(任务队列取数)
START TRANSACTION;
-- 跳过已被其他消费者锁定的任务,取最新10个待处理任务
SELECT id, payload FROM task_queue 
WHERE status = 0 
ORDER BY priority DESC, id 
LIMIT 10 
FOR UPDATE SKIP LOCKED;

-- 更新状态后提交
UPDATE task_queue SET status = 1 WHERE id IN (...);
COMMIT;
3.5.5 事务实战:电商下单完整流程
-- 模拟下单流程(需在事务中执行)
START TRANSACTION;

-- 1. 扣减库存(使用行锁,防止超卖)
UPDATE inventory SET stock = stock - 1 
WHERE product_id = 100 AND stock > 0;

-- 2. 检查扣减结果(影响行数应为1)
IF ROW_COUNT() = 0 THEN
    ROLLBACK;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '库存不足';
END IF;

-- 3. 创建订单
INSERT INTO `order`(user_id, order_no, total_amount, status) 
VALUES(1, 'ORD20260713001', 99.99, 0);

-- 4. 插入订单明细
INSERT INTO order_item(order_id, product_id, quantity, price) 
VALUES(LAST_INSERT_ID(), 100, 1, 99.99);

COMMIT;

知识点延伸

  • 为什么扣库存要 WHERE stock > 0?—— 避免负库存,结合行锁保证原子性。
  • 为什么不先INSERT订单再扣库存?—— 防止订单创建成功但库存扣减失败,导致数据不一致。
  • 高并发下如何优化?—— 使用Redis预扣库存 + 异步队列同步DB,或使用 SELECT ... FOR UPDATE SKIP LOCKED 实现无阻塞队列。

3.6 视图、存储过程、触发器

  • 视图:封装复杂查询,简化权限管理
  • 存储过程:适合批处理,但调试困难,生产慎用
  • 触发器:容易造成隐式逻辑,不建议在高并发中使用

3.7 DCL权限管理

-- 最小权限原则
CREATE USER 'app_read'@'192.168.1.%' IDENTIFIED BY 'password';
GRANT SELECT ON shop.* TO 'app_read'@'192.168.1.%';
REVOKE DELETE ON shop.* FROM 'app_read'@'192.168.1.%';
FLUSH PRIVILEGES;

3.8 Binlog核心体系(2026后端必考)

3.8.1 Binlog三种格式
  1. STATEMENT:记录SQL语句,节省空间,数据不一致风险,淘汰
  2. ROW:记录行变更,精准、无坑、8.0默认,生产唯一推荐
  3. MIXED:混合模式,已淘汰
3.8.2 Binlog核心用途
  • 主从复制
  • 数据恢复
  • 增量同步(Canal、DataX)
  • 审计日志
3.8.3 8.0 Binlog新特性
  • Binlog 持久化 crash-safe(崩溃不丢日志)
  • 支持压缩、事务分组

3.9 分区表(日志型大表首选)

适用场景:日志表、订单流水、统计数据(写多读少,按时间清理归档
注意:高并发写入下存在全局锁竞争,业务高频交易表(如订单主表)仍推荐应用层分库分表
常用分区

  • 按时间范围分区(RANGE)
  • 按ID哈希分区(HASH)

优势:

  • 清理历史数据 DROP PARTITION 秒删(不用delete)
  • 查询只扫描对应分区,性能暴涨

示例:

CREATE TABLE order_log (
  id BIGINT UNSIGNED AUTO_INCREMENT,
  order_id BIGINT UNSIGNED NOT NULL,
  log_time DATETIME NOT NULL,
  content TEXT,
  PRIMARY KEY (id, log_time)
) ENGINE=InnoDB
PARTITION BY RANGE (TO_DAYS(log_time)) (
  PARTITION p202501 VALUES LESS THAN (TO_DAYS('2025-02-01')),
  PARTITION p202502 VALUES LESS THAN (TO_DAYS('2025-03-01')),
  PARTITION p_future VALUES LESS THAN MAXVALUE
);

3.10 SQL执行顺序终极完整版(面试天花板)

FROM → JOIN → WHERE → GROUP BY → 聚合计算 → HAVING → 
WITH/窗口函数 → SELECT → DISTINCT → ORDER BY → LIMIT

📌 注意:窗口函数在HAVING之后、SELECT之前执行,CTE在FROM之前解析。


模块4:运维·架构·面试

4.1 慢查询与日志

-- 开启慢查询日志(生产建议长期开启)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2; -- 超过2秒记录
SET GLOBAL log_queries_not_using_indexes = ON;

4.2 备份恢复

# 逻辑备份(mysqldump)
mysqldump -u root -p --single-transaction --routines --triggers shop > shop_backup.sql

# 物理备份(xtrabackup,适合大数据量)
xtrabackup --backup --target-dir=/backup/mysql/

4.3 主从复制与读写分离

-- 从库配置(my.cnf)
server-id=2
relay-log=mysql-relay-bin
read-only=1

-- 主库创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

-- 从库执行
CHANGE MASTER TO MASTER_HOST='master_ip', MASTER_USER='repl', MASTER_PASSWORD='password', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154;
START SLAVE;

4.4 分库分表基础

  • 垂直分表:将不常用字段或大字段拆分到扩展表
  • 水平分表:按用户ID哈希或时间范围分片
  • ShardingSphere:透明化分库分表,应用层无需感知

4.5 性能压测与监控指标

常用性能指标
指标命令/查询正常范围
QPS/TPSSHOW GLOBAL STATUS LIKE 'Questions';视硬件而定
慢查询比例SHOW GLOBAL STATUS LIKE 'Slow_queries';占比<1%
缓存命中率SHOW STATUS LIKE 'Innodb_buffer_pool_reads%';命中率>95%
锁等待次数SHOW STATUS LIKE 'Innodb_row_lock_waits';越低越好
活跃连接数SHOW PROCESSLIST;小于max_connections的80%
使用sysbench进行压测
# 安装
apt install sysbench

# 准备数据(16个表,每个表100万行)
sysbench /usr/share/sysbench/oltp_read_write.lua --table-size=1000000 --tables=16 prepare

# 运行压测(64个线程,持续60秒)
sysbench /usr/share/sysbench/oltp_read_write.lua --threads=64 --time=60 run

4.6 高频面试题库(精选+场景题)

Q1:MySQL为什么用B+树而不是B树?
A:B+树非叶子节点不存数据,可存放更多索引,树高更低;叶子节点有序链表,范围查询效率极高。

Q2:什么是MVCC?如何实现可重复读?
A:MVCC通过Undo Log保存数据快照,事务开始时生成Read View。可重复读下,每次查询使用同一个Read View,保证看到的数据一致。

Q3:间隙锁是什么?如何解决幻读?
A:间隙锁锁定一个区间,防止其他事务插入新数据。在RR级别下,InnoDB使用Next-Key Lock(行锁+间隙锁)彻底解决幻读。

Q4:如何优化大分页查询?
A:使用延迟关联(先查主键再JOIN原表)或游标分页(仅限上一页/下一页场景)。

Q5:count(*)、count(1)、count(字段)的区别?
A:count(*)统计所有行,包括NULL,MySQL对其做了专门优化,速度最快;count(1)本质相同;count(字段)忽略NULL值。

Q6(场景题):假设有一个订单表,每天新增100万数据,如何设计分表方案?
A:可按用户ID哈希分1024张表(取模),或按时间按月分表。查询时需带上分片键,否则会遍历所有表。可使用ShardingSphere或MyCat透明化分片。

Q7(场景题):线上突然出现大量Waiting for table metadata lock,如何处理?
A:通常是DDL操作或长时间未提交的事务阻塞了后续查询。应先找到阻塞源头(SHOW PROCESSLIST),杀掉长时间未提交的事务或DDL会话,然后优化业务代码,避免在高峰期执行DDL。

Q8(场景题):如何在不重启数据库的情况下,给一个10亿行的表加索引?
A:MySQL 8.0支持Online DDL,ALTER TABLE ... ADD INDEX ... ALGORITHM=INPLACE, LOCK=NONE,允许并发DML。但依然建议在低峰期执行,并使用pt-online-schema-change工具控制负载。

Q9:为什么禁止业务用物理外键?

  1. 高并发下锁范围扩大,极易死锁
  2. 主从延迟导致外键校验异常
  3. 分库分表后外键彻底失效
  4. 微服务架构跨库无法外键
    ✅ 现代架构:业务逻辑一致性替代物理外键。(单库小型后台管理可酌情使用)

Q10:DELETE、TRUNCATE、DROP 三兄弟完整区别(终极版)

  • DELETE:DML、可回滚、不删结构、自增不重置
  • TRUNCATE:DDL、不可回滚、清空数据、重置自增(8.0下若表有外键约束则执行失败
  • DROP:DDL、删表结构+数据、释放空间

Q11:MVCC 到底解决了什么?

  • 解决:脏读、不可重复读
  • 解决不了:写幻读(必须靠锁)

Q12:大表加索引如何不锁表?
8.0:ALTER TABLE t ADD INDEX idx_xxx(col) ALGORITHM=INPLACE, LOCK=NONE;

Q13:线上慢SQL突然暴涨,排查链路?

  1. 慢查询日志
  2. EXPLAIN / EXPLAIN ANALYZE 看type、key、rows、实际耗时
  3. 检查是否索引失效(结合直方图判断数据分布)
  4. 检查是否大分页、大事务
  5. 检查是否锁等待、元数据锁

4.7 2026生产禁止清单(超级实用)

禁止项原因替代方案
❌ TIMESTAMP2038年溢出使用DATETIME
❌ utf8字符集不支持emoji、生僻字使用utf8mb4
❌ MyISAM引擎不支持事务、崩溃不安全使用InnoDB
❌ 物理外键(微服务/分布式)锁竞争、迁移困难逻辑外键(业务保证)
❌ SELECT *浪费IO、无法覆盖索引只查需要的字段
❌ 无索引JOIN多表全表扫描、性能灾难关联字段建索引
❌ 线上大事务锁持有时间长、死锁风险拆分小事务
❌ DELETE全表/UPDATE全表锁表、主从延迟分批处理或TRUNCATE
❌ FLOAT/DOUBLE存金额精度丢失使用DECIMAL

附录:工具清单

工具用途推荐指数
SQLAdvisor索引优化建议⭐⭐⭐⭐
pt-query-digest慢查询分析⭐⭐⭐⭐⭐
DBeaver免费可视化客户端⭐⭐⭐⭐⭐
Navicat商业级客户端⭐⭐⭐⭐
LeetCode SQL题库面试刷题⭐⭐⭐⭐⭐
sysbench性能压测⭐⭐⭐⭐⭐

结语:本教程覆盖了从零基础到大厂生产的完整路径,所有知识均基于MySQL 8.0 LTS,并充分考虑了2026年后的技术趋势。掌握这些内容,你将拥有5年内不过时的数据库能力。祝你学习愉快,早日成为数据库专家!

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/slyn_2004/article/details/162850074

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--