MySQL完整学习手册(视频精华版)

MySQL完整学习手册(赵老师视频精华版)

基于赵老师8个MySQL教学视频 + 数据库运维XMind笔记 + G盘教案

标注说明:【面试必问】 = 面试高频考点 | 【教案补充】 = 教案文档细节补充 | 【知识拓展】 = 视频外MySQL必备知识


第1章:MySQL概述与安装部署

1.1 数据库核心概念

数据库(Database,简称DB)是按照特定格式存储数据的文件集合,本质上是存储在磁盘上的一堆文件。数据库管理系统(DBMS)是专门管理数据库中数据的软件,MySQL、Oracle、PostgreSQL等都属于DBMS。

SQL(Structured Query Language)是操作关系型数据库的标准语言,由IBM于1970年代提出,目前所有主流关系型数据库都支持SQL。

常见关系型数据库

数据库 特点
MySQL / MariaDB 开源、社区活跃、互联网首选
Oracle 商业数据库、金融/电信核心系统
PostgreSQL 开源、功能最丰富、GIS支持强
SQL Server 微软生态、Windows集成
TiDB 国产分布式关系型数据库

【知识拓展】 MySQL和MariaDB的关系:MariaDB是MySQL创始人Monty Widenius在MySQL被Oracle收购后(2009年)创建的MySQL分支,与MySQL高度兼容。MySQL 8.0之后两者差异逐渐增大。

1.2 关系型数据库模型

【面试必问】 关系模型建立在严格的数学基础上,核心三要素:

实体(Entity):现实世界中可区分的对象,对应数据库中的"表"(Table)。

  • 例如:学生、课程、教师

属性(Attribute):实体的特征,对应表中的"列"(Column/Field)。

  • 例如:学生的姓名、学号、年龄

联系(Relationship):实体之间的关系,通过外键实现。

  • 一对一(1:1):一个部门对应一个负责人
  • 一对多(1:N):一个教师教授多门课程,每门课程只有一个教师
  • 多对多(M:N):一个学生选修多门课程,每门课程有多个学生选修(需要中间表)

表结构术语对照

术语 含义
库(Database) 存储数据的容器,包含多张表
表(Table) 由行列组成的二维表格
行(Row/Record) 表中的一条记录,代表一个实体实例
列(Column/Field) 表中的一列,代表一个属性
主键(Primary Key) 唯一标识一行记录的列或列组合

1.3 MySQL版本与生态

【知识拓展】 MySQL版本演进关键节点:

  • MySQL 5.5(2010):InnoDB成为默认引擎
  • MySQL 5.6(2013):GTID复制、Online DDL
  • MySQL 5.7(2015):JSON支持、sys schema、多源复制
  • MySQL 8.0(2018):窗口函数、CTE、原子DDL、caching_sha2_password默认认证【当前企业主流】
  • MySQL 8.4 LTS(2024):长期支持版本

MySQL 8.0核心新特性:

  • 窗口函数(ROW_NUMBER/RANK/DENSE_RANK/LAG/LEAD)
  • 公用表表达式CTE(WITH RECURSIVE)
  • 原子DDL(CREATE/ALTER/DROP不可部分执行)
  • 默认字符集utf8mb4、默认排序规则utf8mb4_0900_ai_ci
  • 隐藏索引(Invisible Index)、降序索引
  • 克隆插件(Clone Plugin)

1.4 RPM安装MySQL

四要素

  • 机器:MySQL服务器(任意Linux主机,如 192.168.100.165)
  • 做什么:通过yum/dnf安装MySQL 8.0服务端
  • 完整命令:如下
  • 为什么:RPM方式自动处理依赖,适合快速标准化部署
bash 复制代码
# 步骤1:安装MySQL Yum仓库
rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm

# 步骤2:安装MySQL服务端和客户端
yum install -y mysql-server mysql

# 步骤3:启动并设置开机自启
systemctl enable --now mysqld

# 步骤4:获取初始root密码(MySQL 8.0首次启动生成随机密码)
grep 'temporary password' /var/log/mysqld.log

# 步骤5:安全初始化(修改root密码、移除匿名用户、禁止远程root登录、删除test库)
mysql_secure_installation

# 步骤6:使用新密码登录验证
mysql -uroot -p

为什么需要mysql_secure_installation:MySQL安装后默认存在安全风险(空密码root、匿名用户、test数据库可被任何人访问),此命令交互式地加固初始安全配置。

MariaDB安装(替代方案)

bash 复制代码
yum install -y mariadb-server mariadb
systemctl enable --now mariadb

1.5 编译安装MySQL

为什么需要编译安装:需要对MySQL进行定制化编译(如指定安装路径、启用/禁用特定存储引擎、优化编译参数)时使用编译安装。适合对性能有极致要求或需要自定义功能的场景。
四要素

  • 机器:MySQL服务器(OpenEuler 24.03 或 CentOS/RHEL 8+)
  • 做什么:源码编译安装MySQL 8.0
  • 完整命令:如下
  • 为什么:编译安装可定制编译参数、安装路径,获得最佳性能
bash 复制代码
# === 环境准备 ===
# 安装编译依赖
dnf install -y gcc gcc-c++ cmake ncurses-devel openssl-devel \
    bison libtirpc-devel rpcgen make

# 创建mysql用户(不允许登录,仅用于运行服务)
useradd -r -s /sbin/nologin mysql

# === 下载并编译 ===
# 下载Boost库(MySQL 8.0编译需要)
wget https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.gz
tar xf boost_1_77_0.tar.gz -C /usr/local/

# 下载MySQL源码
wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.36.tar.gz
tar xf mysql-8.0.36.tar.gz
cd mysql-8.0.36

# 创建编译目录(out-of-source build)
mkdir build && cd build

# CMake配置
cmake .. \
    -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
    -DMYSQL_DATADIR=/data/mysql \
    -DSYSCONFDIR=/etc \
    -DWITH_BOOST=/usr/local/boost_1_77_0 \
    -DDEFAULT_CHARSET=utf8mb4 \
    -DDEFAULT_COLLATION=utf8mb4_0900_ai_ci \
    -DWITH_SSL=system \
    -DWITH_INNOBASE_STORAGE_ENGINE=1 \
    -DWITH_ARCHIVE_STORAGE_ENGINE=1 \
    -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
    -DENABLED_LOCAL_INFILE=1

# 编译(-j 根据CPU核心数调整)
make -j$(nproc)

# 安装
make install

# === 初始化与配置 ===
# 创建数据目录
mkdir -p /data/mysql
chown -R mysql:mysql /usr/local/mysql /data/mysql

# 初始化数据库(生成root随机密码,记下日志中输出的密码)
/usr/local/mysql/bin/mysqld --initialize --user=mysql --datadir=/data/mysql

# 添加环境变量
echo 'export PATH=/usr/local/mysql/bin:$PATH' >> /etc/profile
source /etc/profile

# 创建systemd服务文件
cat > /usr/lib/systemd/system/mysqld.service << 'EOF'
[Unit]
Description=MySQL Server
After=network.target
[Service]
Type=forking
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --daemonize
ExecStop=/usr/local/mysql/bin/mysqladmin -uroot -p shutdown
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now mysqld

cmake关键参数说明

  • CMAKE_INSTALL_PREFIX:安装根目录
  • MYSQL_DATADIR:数据文件存放目录(生产环境建议独立磁盘)
  • DEFAULT_CHARSET=utf8mb4:默认字符集(支持emoji和所有Unicode字符)
  • WITH_BOOST:指定Boost库路径(MySQL 8.0必选)

1.6 安装后验证

bash 复制代码
# 查看版本
mysql -V
# MySQL  Ver 8.0.36 for Linux on x86_64 (Source distribution)

# 查看服务状态
systemctl status mysqld

# 查看监听端口(默认3306)
ss -tlnp | grep 3306

# 连接数据库
mysql -uroot -p

第2章:MySQL配置、默认数据库与SQL语言基础

2.1 MySQL配置文件与目录结构

配置文件my.cnf

安装后MySQL的配置文件在 /etc/my.cnf,使用分组结构 [mysqld][client][mysql] 等。配置优先级(从高到低):

复制代码
/etc/my.cnf → /etc/mysql/my.cnf → ~/.my.cnf

配置示例与核心参数解读

ini 复制代码
[client]
port=3306
socket=/var/lib/mysql/mysql.sock

[mysqld]
# === 基础设置 ===
port=3306                            # 监听端口
datadir=/data/mysql                  # 数据文件目录
socket=/var/lib/mysql/mysql.sock     # 本地连接socket
pid-file=/var/run/mysqld/mysqld.pid # PID文件路径
log-error=/var/log/mysqld.log        # 错误日志路径
basedir=/usr                         # MySQL安装目录

# === 字符集 ===
character-set-server=utf8mb4         # 服务端默认字符集
collation-server=utf8mb4_0900_ai_ci  # 排序规则

# === 连接 ===
max_connections=500                  # 最大连接数
max_connect_errors=100               # 最大连接错误数(防暴力破解)
wait_timeout=600                     # 非交互连接超时(秒)

# === InnoDB ===
innodb_buffer_pool_size=2G           # 缓冲池大小(设为物理内存的50%-70%)
innodb_log_file_size=512M            # 单个Redo Log文件大小
innodb_flush_log_at_trx_commit=1     # 事务提交时刷盘策略
innodb_file_per_table=ON             # 每表独立表空间

# === binlog ===
log-bin=mysql-bin                        # 开启二进制日志(主从复制必需)
binlog_format=ROW                        # binlog格式(STATEMENT/ROW/MIXED)
expire_logs_days=7                       # binlog保留天数
max_binlog_size=1G                       # 单个binlog文件上限

# === slow log ===
slow_query_log=ON                        # 开启慢查询日志
slow_query_log_file=/var/log/mysql-slow.log
long_query_time=2                        # 超过2秒计为慢查询

【面试必问】 innodb_flush_log_at_trx_commit 的三个值:

行为 性能 安全性
0 每秒刷一次redo log(OS刷盘) 最快 可能丢失1秒数据
1 每次提交都刷盘(fsync) 最慢 最安全,ACID保证
2 每次提交写OS缓存,每秒刷盘 中等 机器宕机不丢,OS宕机丢1秒

生产环境建议值:1(金融)或 2(互联网,可接受1秒内数据丢失)。

目录结构

RPM安装后的关键目录:

复制代码
/usr/bin/              # 客户端工具 (mysql, mysqladmin, mysqldump...)
/usr/sbin/             # 服务端程序 (mysqld)
/var/lib/mysql/        # 数据目录 (datadir)
/etc/my.cnf            # 配置文件
/var/log/mysqld.log    # 错误日志
/var/run/mysqld/       # socket和pid文件

2.2 MySQL四大默认数据库

SHOW DATABASES; 可以看到4个(MariaDB则为5个)默认数据库:

数据库 作用 存储内容
information_schema 元数据信息库 68个视图,记录所有库/表/列/索引/权限等元数据
mysql 系统核心库 user表(用户权限)、db表(库级权限)、tables_privcolumns_priv
performance_schema 性能监控库 服务器运行时状态、等待事件、内存使用、SQL执行统计
sys 诊断辅助库(5.7+) 基于performance_schema的易读视图,如sys.schema_unused_indexes

为什么需要理解这四个库 :排错时经常需要查information_schema.PROCESSLIST看连接、查mysql.user看权限、查performance_schema分析性能瓶颈。

关键查询示例

sql 复制代码
-- 查看所有数据库
SHOW DATABASES;

-- 查看当前连接
SELECT * FROM information_schema.PROCESSLIST;

-- 查看所有用户和主机
SELECT user, host FROM mysql.user;

-- 查找未使用的索引
SELECT * FROM sys.schema_unused_indexes;

2.3 SQL语言四大分类

【面试必问】 SQL语句按功能分为四大类:

分类 全称 核心命令 作用
DDL Data Definition Language CREATE, ALTER, DROP, TRUNCATE, RENAME 定义库/表/索引等数据库对象结构
DML Data Manipulation Language INSERT, UPDATE, DELETE 操作表中数据
DQL Data Query Language SELECT 查询数据
DCL Data Control Language GRANT, REVOKE 控制用户权限
TCL Transaction Control Language COMMIT, ROLLBACK, SAVEPOINT 事务控制

DDL vs DML 关键区别

  • DDL操作自动提交(不可回滚),执行后立即生效
  • DML操作在事务中可回滚(需显式开启事务)
  • TRUNCATE 属于DDL,速度快但不可回滚;DELETE 属于DML,可回滚但逐行删除较慢

2.4 MySQL常用数据类型

数值类型

类型 范围(有符号) 存储 适用场景
TINYINT -128~127 1字节 状态码、布尔值(0/1)
SMALLINT -32768~32767 2字节 年龄、数量
INT / INTEGER -21亿~21亿 4字节 主键ID、计数
BIGINT -9.2E18~9.2E18 8字节 大表主键、时间戳
FLOAT(M,D) 单精度浮点 4字节 科学计算(不精确)
DOUBLE(M,D) 双精度浮点 8字节 高精度科学计算
DECIMAL(M,D) 精确小数 变长 金额(必须用这个)

【面试必问】 为什么金额不用FLOAT/DOUBLE而用DECIMAL?因为浮点数在二进制中无法精确表示十进制小数,例如 0.1+0.2=0.30000000000000004,会导致金额计算误差。DECIMAL以字符串形式存储,精确无误差。

字符串类型

类型 最大长度 特点
CHAR(N) 255字符 定长,用空格填充,查询最快
VARCHAR(N) 65535字节 变长,按实际长度+1~2字节存储,节省空间
TEXT 65535字符 大文本,不能有默认值
MEDIUMTEXT 16MB 中型文本
LONGTEXT 4GB 超长文本
BLOB 65535字节 二进制大对象(存文件/图片)
ENUM 65535个值 枚举类型(选一)

CHAR vs VARCHAR:CHAR适合固定长度的短字符串(如MD5哈希32位、身份证号18位),VARCHAR适合变长字符串(姓名、邮箱)。CHAR读取速度快但浪费空间,VARCHAR省空间但需要额外字节记录长度。

日期时间类型

类型 格式 范围 存储 时区
DATE YYYY-MM-DD 1000-01-01 ~ 9999-12-31 3字节 无关
TIME HH:MM:SS -838:59:59 ~ 838:59:59 3字节 无关
DATETIME YYYY-MM-DD HH:MM:SS 1000~9999 5字节(旧) 可变(新) 无关
TIMESTAMP 1970-01-01 00:00:01 ~ 2038-01-19 Unix时间戳 4字节 随系统时区自动转换
YEAR YYYY 1901~2155 1字节 ---

TIMESTAMP vs DATETIME:TIMESTAMP受2038年问题限制(32位),但会自动根据时区转换,适合记录"发生时间";DATETIME不随时区变,适合记录"日历时间"(如生日)。

2.5 JSON数据类型(MySQL 5.7+)

【教案补充】

sql 复制代码
-- 创建含JSON列的表
CREATE TABLE configs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    settings JSON
);

-- 插入JSON数据
INSERT INTO configs (settings) VALUES ('{"lang": "zh", "theme": "dark"}');

-- JSON查询(-> 返回JSON,->> 返回文本)
SELECT settings->>'$.lang' AS lang FROM configs;

-- JSON更新
UPDATE configs SET settings = JSON_SET(settings, '$.theme', 'light') WHERE id=1;

第3章:数据库与表操作、用户权限管理

3.1 数据库操作(DDL)

sql 复制代码
-- 创建数据库(指定字符集和排序规则)
CREATE DATABASE school
    DEFAULT CHARACTER SET utf8mb4
    DEFAULT COLLATE utf8mb4_0900_ai_ci;

-- 查看所有数据库
SHOW DATABASES;

-- 查看建库语句
SHOW CREATE DATABASE school;

-- 选择/切换数据库
USE school;

-- 修改数据库字符集
ALTER DATABASE school CHARACTER SET utf8mb4;

-- 删除数据库(不可回滚!)
DROP DATABASE school;

3.2 表操作(DDL)

创建表

sql 复制代码
CREATE TABLE student (
    id INT AUTO_INCREMENT COMMENT '学号',
    name VARCHAR(20) NOT NULL COMMENT '姓名',
    gender ENUM('男','女') DEFAULT '男' COMMENT '性别',
    birth DATE COMMENT '出生日期',
    phone CHAR(11) COMMENT '手机号',
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    PRIMARY KEY (id),
    UNIQUE KEY uk_phone (phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';

修改表结构

sql 复制代码
-- 添加列
ALTER TABLE student ADD COLUMN email VARCHAR(50);

-- 修改列类型
ALTER TABLE student MODIFY COLUMN email VARCHAR(100);

-- 重命名列(同时改类型)
ALTER TABLE student CHANGE COLUMN email mail_addr VARCHAR(80);

-- 删除列
ALTER TABLE student DROP COLUMN mail_addr;

-- 添加索引
ALTER TABLE student ADD INDEX idx_name (name);

-- 重命名表
RENAME TABLE student TO stu;

-- 查看表结构
DESC stu;

删除表

sql 复制代码
-- 逐行删除数据,可回滚(DML)
DELETE FROM stu;

-- 清空表,DDL,不可回滚,重置AUTO_INCREMENT
TRUNCATE TABLE stu;

-- 删除表结构+数据(DDL)
DROP TABLE stu;

【面试必问】TRUNCATE vs DELETE vs DROP

操作 类型 可回滚 速度 AUTO_INCREMENT WHERE
DELETE DML ✅(事务中) 慢(逐行+写undo) 保留当前值
TRUNCATE DDL 极快(重建数据文件) 重置为1
DROP DDL --- ---

3.3 数据操作(DML / DQL)

插入数据

sql 复制代码
-- 单行插入
INSERT INTO student (name, gender, birth, phone)
VALUES ('张三', '男', '2000-01-15', '13800138001');

-- 批量插入(性能更优)
INSERT INTO student (name, gender, birth, phone) VALUES
    ('李四', '女', '2001-03-20', '13800138002'),
    ('王五', '男', '1999-12-10', '13800138003');

-- 从查询结果插入
INSERT INTO student_archive SELECT * FROM student WHERE birth < '2000-01-01';

更新数据

sql 复制代码
-- 更新单行(务必加WHERE!)
UPDATE student SET phone='13900139001' WHERE id=1;

-- 批量更新
UPDATE student SET gender='女' WHERE name LIKE '张%';

-- ⚠️ 不加WHERE会更新全表!

删除数据

sql 复制代码
-- 删除指定行
DELETE FROM student WHERE id=3;

-- 删除全表数据(逐行删,大表很慢)
DELETE FROM student;

查询数据(DQL)

sql 复制代码
-- 全表查询
SELECT * FROM student;

-- 指定列
SELECT id, name, phone FROM student;

-- 条件查询
SELECT * FROM student WHERE gender='男' AND birth > '2000-01-01';

-- 模糊查询
SELECT * FROM student WHERE name LIKE '张%';  -- 以"张"开头
SELECT * FROM student WHERE name LIKE '%三';  -- 以"三"结尾

-- 排序
SELECT * FROM student ORDER BY birth DESC;

-- 分页
SELECT * FROM student LIMIT 10 OFFSET 20;  -- 第3页,每页10条

-- 聚合
SELECT gender, COUNT(*) AS cnt FROM student GROUP BY gender;

-- 聚合后过滤(HAVING vs WHERE:WHERE在分组前过滤,HAVING在分组后过滤)
SELECT gender, COUNT(*) AS cnt FROM student
    GROUP BY gender HAVING cnt > 2;

3.4 用户权限管理

用户管理

四要素

  • 机器:MySQL服务器
  • 做什么:创建用户并授予最小必要权限
  • 完整命令:如下
  • 为什么:生产环境严禁用root远程连接,应按需创建专用账号并遵循最小权限原则
sql 复制代码
-- 登录(root本地)
mysql -uroot -p

-- 创建用户(MySQL 8.0默认caching_sha2_password)
CREATE USER 'appuser'@'%' IDENTIFIED BY 'StrongP@ss123';

-- 创建用户(指定mysql_native_password,兼容老旧客户端)
CREATE USER 'appuser'@'192.168.100.%' IDENTIFIED WITH mysql_native_password BY 'StrongP@ss123';

-- 查看所有用户
SELECT user, host, plugin FROM mysql.user;

-- 修改密码
ALTER USER 'appuser'@'%' IDENTIFIED BY 'NewP@ss456';

-- 锁定/解锁用户
ALTER USER 'appuser'@'%' ACCOUNT LOCK;
ALTER USER 'appuser'@'%' ACCOUNT UNLOCK;

-- 删除用户
DROP USER 'appuser'@'%';

【知识拓展】 MySQL 8.0默认认证插件从mysql_native_password改为caching_sha2_password,老版本客户端(如Navicat 11以下)连接会报错。解决方案:①升级客户端;②创建用户时指定WITH mysql_native_password

权限授予与回收

sql 复制代码
-- 授予权限
-- 给appuser授予school库所有权限
GRANT ALL PRIVILEGES ON school.* TO 'appuser'@'%';

-- 只给SELECT查询权限
GRANT SELECT ON school.* TO 'readonly'@'%';

-- 给特定表的特定列权限
GRANT SELECT (name, phone) ON school.student TO 'minuser'@'%';

-- 授予SUPER权限(需要全局级别)
GRANT SUPER, REPLICATION SLAVE ON *.* TO 'repl'@'%';

-- 查看用户权限
SHOW GRANTS FOR 'appuser'@'%';

-- 回收权限
REVOKE DELETE ON school.* FROM 'appuser'@'%';

-- 刷新权限(修改权限表后执行)
FLUSH PRIVILEGES;

常见授权场景

角色 权限 命令示例
DBA ALL PRIVILEGES ON . GRANT ALL ON *.* TO 'dba'@'localhost';
应用读写 SELECT, INSERT, UPDATE, DELETE GRANT SELECT,INSERT,UPDATE,DELETE ON appdb.* TO 'app'@'%';
只读用户 SELECT GRANT SELECT ON appdb.* TO 'reader'@'%';
主从复制 REPLICATION SLAVE GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
备份用户 SELECT, RELOAD, LOCK TABLES, PROCESS GRANT SELECT,RELOAD,LOCK TABLES,PROCESS ON *.* TO 'backup'@'localhost';

最小权限原则:每个用户只授予其完成任务所必需的权限。例如:备份用户不需要DELETE,只读用户不需要INSERT/UPDATE/DELETE。


第4章:MySQL备份与恢复

4.1 备份策略基础

备份的目的是灾难恢复(Disaster Recovery),核心指标:

  • RPO(Recovery Point Objective):恢复点目标------能容忍丢失多少数据(越小越好)
  • RTO(Recovery Time Objective):恢复时间目标------多长时间能恢复服务
备份类型 说明 优点 缺点
逻辑备份 导出SQL语句 跨版本兼容、可读可编辑 慢、备份时锁表
物理备份 复制数据文件 快、不锁表(热备份) 跨平台/版本兼容性差
全量备份 备份全部数据 恢复最简单 耗时长、空间大
增量备份 只备份上次备份以来变化的数据 空间小、速度快 恢复需叠加多次备份
热备份 数据库运行时备份 不影响业务 需要特定工具支持
冷备份 停库后备份 最安全最一致 需要停机窗口

4.2 逻辑备份:mysqldump

【面试必问】mysqldump原理 :通过SQL语句逐条读取数据并生成INSERT语句。备份期间对表加读锁(FLUSH TABLES WITH READ LOCK),InnoDB可通过--single-transaction避免锁表。

bash 复制代码
# === 全库备份 ===
# 四要素:备份服务器 / 全库备份 / 以下命令 / 用于灾难恢复
mysqldump -uroot -p --all-databases --single-transaction --routines --triggers \
    > /backup/full_$(date +%Y%m%d).sql

# === 单库备份 ===
mysqldump -uroot -p --databases school --single-transaction \
    > /backup/school_$(date +%Y%m%d).sql

# === 单表备份(只备份结构和数据)===
mysqldump -uroot -p school student \
    > /backup/student_$(date +%Y%m%d).sql

# === 只导出表结构 ===
mysqldump -uroot -p --no-data school > /backup/school_schema.sql

# === 只导出数据(不含建表语句)===
mysqldump -uroot -p --no-create-info school student > /backup/student_data.sql

关键参数

参数 作用
--single-transaction InnoDB热备份关键参数,开启事务保证一致性读,不发锁表
--routines 导出存储过程和函数
--triggers 导出触发器
--master-data=2 在备份SQL中记录binlog位置(注释形式),恢复后可用于搭建主从
--flush-logs 备份前刷新日志,生成新binlog文件
--all-databases 备份所有库(含mysql系统库)

4.3 物理备份:XtraBackup

【面试必问】XtraBackup vs mysqldump

维度 XtraBackup mysqldump
原理 直接复制InnoDB数据文件 + redo log 逐行读数据生成INSERT SQL
锁表 ❌ 不锁表(热备份) ⚠️ MyISAM表会锁(加--single-transaction后InnoDB不锁)
速度 快(与数据文件大小成正比) 慢(需逐行导出)
恢复速度 快(直接复制回) 慢(逐行INSERT回放)
增量备份 ✅ 原生支持 ❌ 需结合binlog
兼容性 同版本/同平台 跨版本跨平台
适用场景 大库(>10GB)、生产环境 小库、逻辑迁移、跨版本升级

XtraBackup安装

bash 复制代码
# RHEL/CentOS 8+
dnf install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
percona-release enable-only tools release
dnf install -y percona-xtrabackup-80

XtraBackup全量备份

四要素

  • 机器:MySQL服务器(对数据文件有读取权限)
  • 做什么:创建全量物理热备份
  • 完整命令:如下
  • 为什么:不锁表、速度快,适合大库生产环境
bash 复制代码
# 创建备份
xtrabackup --backup \
    --user=root --password='YourP@ss' \
    --target-dir=/backup/full_$(date +%Y%m%d) \
    --datadir=/data/mysql

# 准备备份(Apply Redo Log,使备份数据一致)
xtrabackup --prepare --target-dir=/backup/full_20260607

# 恢复(先停MySQL,清空原数据目录)
systemctl stop mysqld
rm -rf /data/mysql/*
xtrabackup --copy-back --target-dir=/backup/full_20260607
chown -R mysql:mysql /data/mysql
systemctl start mysqld

XtraBackup增量备份

bash 复制代码
# 在全量备份基础上做增量
xtrabackup --backup \
    --user=root --password='YourP@ss' \
    --target-dir=/backup/inc_$(date +%Y%m%d) \
    --incremental-basedir=/backup/full_20260607

# 恢复增量:先prepare全量(--apply-log-only),再合并增量,最后--prepare完成
xtrabackup --prepare --apply-log-only --target-dir=/backup/full_20260607
xtrabackup --prepare --target-dir=/backup/full_20260607 \
    --incremental-dir=/backup/inc_20260607
# 最后 --copy-back 恢复

4.4 binlog时间点恢复

binlog记录了所有数据变更,可实现任意时间点恢复。

bash 复制代码
# 查看当前binlog文件和位置
mysql -uroot -p -e "SHOW MASTER STATUS;"

# 解析binlog(确认误操作位置)
mysqlbinlog --base64-output=DECODE-ROWS -v /data/mysql/mysql-bin.000003 | less

# 恢复到误操作前一刻
mysqlbinlog --stop-datetime="2026-06-07 14:30:00" /data/mysql/mysql-bin.000003 | mysql -uroot -p

# 跳过误操作,恢复之后的数据
mysqlbinlog --start-datetime="2026-06-07 14:31:00" /data/mysql/mysql-bin.000003 | mysql -uroot -p

# 按位置点恢复(更精确)
mysqlbinlog --stop-position=123456 /data/mysql/mysql-bin.000003 | mysql -uroot -p

4.5 生产环境备份策略推荐

频率 类型 工具 保留
每天凌晨 全量 XtraBackup 7天
每4小时 增量 XtraBackup 3天
实时 binlog 系统自带 7天(expire_logs_days=7)
每周日 mysqldump mysqldump 30天(异地)

为什么需要两种备份并存:XtraBackup快速恢复,mysqldump跨版本可读。全量+增量+binlog组合可满足RPO≈0(丢失<1秒)的需求。

4.6 压缩备份与自动化脚本

bash 复制代码
# 压缩备份(节省空间)
mysqldump -uroot -p --all-databases --single-transaction | gzip > /backup/full.sql.gz

# 解压恢复
gunzip < /backup/full.sql.gz | mysql -uroot -p

定时备份脚本示例

bash 复制代码
#!/bin/bash
# 保存为 /usr/local/bin/mysql_backup.sh,crontab 定时执行
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
KEEP_DAYS=7

mkdir -p $BACKUP_DIR

# XtraBackup全量
xtrabackup --backup --user=backup --password='xxx' \
    --target-dir=$BACKUP_DIR/full_$DATE

# 清理旧备份
find $BACKUP_DIR -name "full_*" -type d -mtime +$KEEP_DAYS -exec rm -rf {} \;
bash 复制代码
# 添加到crontab(每天凌晨2点执行)
# crontab -e
0 2 * * * /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

第5章:数据库高级特性------主键、外键、索引、Check约束

5.1 主键PRIMARY KEY

主键是表中唯一标识每一行记录的列或列组合。一张表只能有一个主键,主键值不能为NULL且不能重复。

创建主键

sql 复制代码
-- 建表时指定
CREATE TABLE course (
    id INT AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    PRIMARY KEY (id)
);

-- 建表后添加
ALTER TABLE course ADD PRIMARY KEY (id);

-- 修改自增主键起始值
ALTER TABLE course AUTO_INCREMENT=1000;

【面试必问】主键与InnoDB聚簇索引的关系:InnoDB中,主键就是聚簇索引(Clustered Index),表数据按主键B+Tree的叶子节点物理存储。如果没有显式定义主键,InnoDB会选择第一个UNIQUE NOT NULL索引作为聚簇索引;如果都没有,InnoDB会自动生成一个6字节的隐藏row_id作为聚簇索引。

为什么自增INT是最佳主键:自增ID按顺序插入B+Tree,减少页分裂(Page Split),保证了聚簇索引的插入效率和存储密度。UUID作为主键会导致随机插入、频繁页分裂、索引碎片化。

5.2 外键FOREIGN KEY

外键用于建立表与表之间的关系,保证引用完整性。

sql 复制代码
CREATE TABLE score (
    id INT AUTO_INCREMENT PRIMARY KEY,
    stu_id INT NOT NULL,
    course_id INT NOT NULL,
    score DECIMAL(5,2),
    -- 外键约束
    CONSTRAINT fk_score_student FOREIGN KEY (stu_id) REFERENCES student(id)
        ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES course(id)
        ON DELETE RESTRICT ON UPDATE CASCADE
);

级联操作

选项 说明
CASCADE 父表更新/删除时,子表同步更新/删除
SET NULL 父表删除时,子表外键列置NULL
RESTRICT / NO ACTION 如果子表有引用,拒绝父表的更新/删除
SET DEFAULT 父表更新/删除时,子表外键设为默认值

【知识拓展】生产环境中外键的争议:互联网公司通常不在数据库层面使用外键约束(在应用层保证引用完整性),原因是外键在高并发写入时会带来额外的锁开销和性能损耗。

5.3 索引(Index)

【面试必问------全章重点】

5.3.1 索引分类

按数据结构分
类型 底层结构 特点 适用场景
B+Tree 多路平衡搜索树 有序、支持范围查询 InnoDB默认、最常用
Hash 哈希表 O(1)等值查询 MEMORY引擎、等值查询
FullText 倒排索引 全文搜索 大文本搜索(如文章内容)

【面试必问】B+Tree为什么是MySQL索引的最佳选择

  1. 高度低:B+Tree的扇出率(fanout)极高,三层即可索引千万级数据。查找一个值只需3次磁盘I/O
  2. 叶子节点形成有序链表 :所有数据存在叶子节点,叶子节点之间用双向链表连接,天然支持范围查询和排序(ORDER BY/BETWEEN
  3. 非叶子节点只存索引键:不存数据,一个节点能容纳更多索引键,进一步降低树高
  4. 与B树的区别:B树所有节点都存数据,B+树只在叶子节点存数据;B+树叶子节点有链表,支持高效范围扫描
  5. 为什么不选红黑树/AVL树:二叉树在磁盘场景下高度太大(百万数据约20层→20次I/O),B+树只需要3层
按物理存储分
类型 说明 InnoDB中
聚簇索引 数据按索引顺序物理存储 主键就是聚簇索引
二级索引(辅助索引) 叶子节点存储主键值 回表查询

【面试必问】聚簇索引 vs 二级索引

  • 聚簇索引的叶子节点存的是完整行数据
  • 二级索引的叶子节点存的是主键值
  • 通过二级索引查询时,先找到主键值,再回表(去聚簇索引中)查完整数据
  • 覆盖索引:如果查询的列都在二级索引中,不需要回表,性能最高
按字段特性分
类型 特点
主键索引 唯一、非空、每表一个
唯一索引(UNIQUE) 值唯一,允许NULL(多个NULL不冲突)
普通索引 无约束,加速查询
前缀索引 对列的前N个字符建索引(节省空间)
全文索引 用于全文搜索

5.3.2 索引操作

sql 复制代码
-- 创建普通索引
CREATE INDEX idx_name ON student(name);

-- 创建唯一索引
CREATE UNIQUE INDEX uk_phone ON student(phone);

-- 创建联合索引
CREATE INDEX idx_name_age ON student(name, age);

-- 创建前缀索引(前10个字符)
CREATE INDEX idx_email_prefix ON student(email(10));

-- 查看表的所有索引
SHOW INDEX FROM student;

-- 删除索引
DROP INDEX idx_name ON student;
ALTER TABLE student DROP INDEX idx_name;

5.3.3 联合索引与最左匹配原则

【面试必问】最左匹配原则:联合索引中,查询条件必须从索引的最左列开始匹配,且不能跳过中间的列,索引才能被有效使用。

sql 复制代码
-- 联合索引: (a, b, c)
CREATE INDEX idx_abc ON test(a, b, c);

-- ✅ 使用索引:从最左a开始匹配
SELECT * FROM test WHERE a = 1;
SELECT * FROM test WHERE a = 1 AND b = 2;
SELECT * FROM test WHERE a = 1 AND b = 2 AND c = 3;
SELECT * FROM test WHERE a = 1 AND c = 3;  -- 只用到a(c被跳过)

-- ❌ 不使用索引:未从最左开始
SELECT * FROM test WHERE b = 2;
SELECT * FROM test WHERE c = 3;
SELECT * FROM test WHERE b = 2 AND c = 3;

联合索引设计原则 :把区分度最高、最常用于等值查询的列放在最左边。例如 (status, create_time) vs (create_time, status)------如果status只有几个值,create_time区分度高,后者通常更好(前提是查询总带create_time)。

5.3.4 索引失效的常见场景

【面试必问】哪些情况会导致索引失效

场景 示例 原因
前导通配符模糊查询 LIKE '%abc' / LIKE '%abc%' B+Tree只能按前缀匹配
对索引列使用函数 WHERE YEAR(birth)=2000 破坏了索引的有序性
对索引列进行运算 WHERE id+1=100 同上
隐式类型转换 WHERE phone=13800138001(phone是CHAR) 字符串→数字转换导致索引失效
OR连接非索引列 WHERE a=1 OR b=2(b没有索引) 需要全表扫描
联合索引不满足最左匹配 见上节 跳过了最左列
使用 != 或 <> WHERE status != 'done' 可能退化为全表扫描(取决于优化器)
IS NULL / IS NOT NULL 取决于数据分布 索引不存NULL值(InnoDB存)

LIKE 'abc%' 可以使用索引:因为这是以"abc"为前缀的匹配,B+Tree可以定位到"abc"开头的第一个位置,顺序扫描即可。

5.3.5 EXPLAIN执行计划

【面试必问】 EXPLAIN 是分析SQL性能的核心工具。

sql 复制代码
EXPLAIN SELECT * FROM student WHERE name = '张三';

关键字段解读

字段 含义
id 查询序号(数字越大越先执行,相同从上到下)
select_type SIMPLE(简单查询) / PRIMARY(外层) / SUBQUERY(子查询) / DERIVED(派生表)
table 访问的表名
type 访问类型(最重要!从优到劣)
possible_keys 可能使用的索引
key 实际使用的索引
key_len 使用的索引长度(字节),可判断联合索引用了几个列
ref 与索引比较的列或常量
rows 估算需要扫描的行数
filtered 按条件过滤后的行数百分比
Extra 额外信息(Using index=覆盖索引/Using filesort=文件排序/Using temporary=临时表)

【面试必问】type字段从优到劣

复制代码
system > const > eq_ref > ref > range > index > ALL
type 说明 示例
const 通过主键或唯一索引匹配到一行 WHERE id = 1
eq_ref 关联查询中,每个关联键只匹配一行 JOIN中ON主键
ref 非唯一索引等值查询 WHERE name = '张三'
range 索引范围扫描 WHERE id > 100 AND id < 200
index 全索引扫描(比ALL好,比range差) SELECT name FROM student(走name索引)
ALL 全表扫描 无索引或优化器选择全表扫描

Extra中的关键提示

  • Using index(覆盖索引):最优,查询列全在索引中,不需要回表
  • Using index condition(ICP):索引条件下推,在引擎层过滤数据
  • Using filesort需要优化,数据在内存/磁盘排序
  • Using temporary需要优化,使用了临时表

5.4 Check约束

约束字段值必须满足指定条件(MySQL 8.0.16+ 真正支持)。

sql 复制代码
-- 创建带Check约束的表
CREATE TABLE employee (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    age TINYINT CHECK (age >= 18 AND age <= 65),
    salary DECIMAL(10,2) CHECK (salary > 0)
);

-- 查看约束
SELECT * FROM information_schema.CHECK_CONSTRAINTS;

-- 违反约束时会报错
-- INSERT INTO employee(name, age) VALUES ('张三', 15);  -- ERROR: Check constraint violated

第6章:存储过程、触发器、事务与锁机制

6.1 存储过程

存储过程是一组预编译的SQL语句集合,存储在数据库服务端,可重复调用。减少了网络传输和SQL解析开销。

创建和调用

sql 复制代码
-- 修改分隔符(避免分号被解析为语句结束)
DELIMITER //

CREATE PROCEDURE get_students_by_gender(IN g ENUM('男','女'))
BEGIN
    SELECT * FROM student WHERE gender = g;
END //

DELIMITER ;

-- 调用
CALL get_students_by_gender('男');

-- 带输出参数的存储过程
DELIMITER //

CREATE PROCEDURE count_by_gender(IN g ENUM('男','女'), OUT cnt INT)
BEGIN
    SELECT COUNT(*) INTO cnt FROM student WHERE gender = g;
END //

DELIMITER ;

CALL count_by_gender('男', @result);
SELECT @result;

-- 删除
DROP PROCEDURE IF EXISTS get_students_by_gender;

6.2 触发器

触发器是在表上发生INSERT/UPDATE/DELETE时自动执行的SQL代码块。

触发器的六种类型(时机×操作):BEFORE INSERT / AFTER INSERT / BEFORE UPDATE / AFTER UPDATE / BEFORE DELETE / AFTER DELETE

sql 复制代码
-- 创建日志表
CREATE TABLE stu_log (
    id INT AUTO_INCREMENT PRIMARY KEY,
    stu_id INT,
    action VARCHAR(10),
    old_name VARCHAR(50),
    new_name VARCHAR(50),
    change_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 创建AFTER UPDATE触发器
DELIMITER //

CREATE TRIGGER trg_student_update
AFTER UPDATE ON student
FOR EACH ROW
BEGIN
    INSERT INTO stu_log(stu_id, action, old_name, new_name)
    VALUES (NEW.id, 'UPDATE', OLD.name, NEW.name);
END //

DELIMITER ;

-- NEW 和 OLD 关键字:
-- INSERT: 只有 NEW(新插入的行)
-- DELETE: 只有 OLD(被删除的行)
-- UPDATE: NEW=更新后的值,OLD=更新前的值

-- 查看触发器
SHOW TRIGGERS;

-- 删除
DROP TRIGGER IF EXISTS trg_student_update;

生产环境建议:触发器会增加数据库的隐性逻辑复杂度,调试困难,且大量触发时影响性能。现代架构倾向于在应用层处理这类逻辑。

6.3 事务(Transaction)

【面试必问------全章重点】

6.3.1 ACID特性

事务是数据库操作的最小执行单元,要么全部成功、要么全部失败。核心是ACID四大特性:

特性 含义 InnoDB实现方式
A 原子性 事务中的操作要么全做、要么全不做 Undo Log(回滚日志)
C 一致性 事务执行前后,数据库都处于一致状态 A+I+D共同保障
I 隔离性 并发事务之间互不干扰 MVCC + 锁机制
D 持久性 事务提交后数据永久保存 Redo Log(重做日志)

6.3.2 事务控制命令

sql 复制代码
-- 开启事务(三种方式等价)
START TRANSACTION;
-- 或
BEGIN;

-- 执行一系列操作
INSERT INTO student(name) VALUES('张三');
UPDATE student SET phone='13800001111' WHERE id=1;

-- 提交(持久化)
COMMIT;

-- 回滚(撤销)
ROLLBACK;

-- 设置回滚点
SAVEPOINT sp1;
-- ... 操作 ...
ROLLBACK TO SAVEPOINT sp1;  -- 回滚到sp1,sp1之后的操作被撤销

-- 查看当前是否自动提交
SELECT @@autocommit;  -- 默认ON(每条语句自动提交)
-- 关闭自动提交(会话级)
SET autocommit = 0;

6.3.3 事务并发问题

多个事务同时操作同一数据时会出现三种问题:

问题 描述 示例
脏读 读到其他事务未提交的修改 事务B读到事务A修改但未提交的数据
不可重复读 同一事务两次读取,值不一样 事务A两次读同一行,中间事务B修改并提交了
幻读 同一事务两次范围查询,行数不一样 事务A两次SELECT COUNT(*),中间事务B新增了数据

6.3.4 四种事务隔离级别

【面试必问------必考!】

隔离级别 脏读 不可重复读 幻读 实现
READ UNCOMMITTED(读未提交) 无锁
READ COMMITTED(读已提交) 每次SELECT创建新Read View
REPEATABLE READ(可重复读) ✅(InnoDB中) 事务开始时创建Read View + 间隙锁
SERIALIZABLE(串行化) 所有SELECT自动加共享锁

MySQL默认隔离级别是REPEATABLE READ 。在InnoDB中,RR级别通过MVCC + 间隙锁(Gap Lock) 解决了幻读问题,这是MySQL独有的设计。

设置和查看隔离级别

sql 复制代码
-- 查看全局/会话隔离级别
SELECT @@global.transaction_isolation;
SELECT @@session.transaction_isolation;

-- 设置会话级隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 设置全局(重启后生效,永久设置需改my.cnf)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

6.4 MVCC(多版本并发控制)

【面试必问------MVCC是面试高频考点】

MVCC是InnoDB实现高并发的核心机制。核心思想:不对数据加锁,而是维护数据的多个版本,让读操作不阻塞写操作、写操作不阻塞读操作。

6.4.1 MVCC三要素

组件 作用
隐藏字段 每行数据包含 DB_TRX_ID(最后一次修改的事务ID)、DB_ROLL_PTR(回滚指针)、DB_ROW_ID(隐藏主键)
Undo Log 记录数据的历史版本,通过 DB_ROLL_PTR 串联成版本链
Read View 事务开始时的"快照",记录当前活跃事务列表,用于判断版本可见性

6.4.2 Read View可见性判断

事务读取某行数据时,通过Read View判断应该看到哪个版本(沿Undo Log版本链往回找):

  1. 如果版本的事务ID = 当前事务ID → 可见(自己的修改)
  2. 如果版本的事务ID < 当前活跃事务的最小ID → 可见(该事务在Read View创建前已提交)
  3. 如果版本的事务ID > 当前活跃事务的最大ID → 不可见(该事务在Read View创建后开始)
  4. 如果版本的事务ID在活跃列表中 → 不可见(该事务未提交)

RC vs RR的Read View差异

  • RC(读已提交):每次SELECT都创建新的Read View,所以能读到其他事务已提交的修改
  • RR(可重复读):事务中的第一次SELECT创建Read View,之后复用同一个,所以每次读到的数据一致

6.5 InnoDB锁机制

【面试必问】

6.5.1 锁的类型

锁类型 说明 互斥
共享锁(S锁 / 读锁) 允许其他事务读,不允许写 S与X互斥,S与S兼容
排他锁(X锁 / 写锁) 不允许其他事务读或写 X与S、X互斥
意向共享锁(IS) 表级锁,表示打算在行上加S锁 表级
意向排他锁(IX) 表级锁,表示打算在行上加X锁 表级
记录锁(Record Lock) 锁定单行记录的索引 行级
间隙锁(Gap Lock) 锁定索引记录之间的间隙 防止插入,RR级别特有
临键锁(Next-Key Lock) 记录锁 + 间隙锁的组合 InnoDB RR级别的默认行锁
sql 复制代码
-- 显式加共享锁
SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE;  -- MySQL 8.0
-- 或
SELECT * FROM student WHERE id=1 FOR SHARE;

-- 显式加排他锁
SELECT * FROM student WHERE id=1 FOR UPDATE;

【面试必问】间隙锁(Gap Lock)什么时候触发

  • 仅在RR隔离级别下生效
  • 对索引列进行等值查询时,如果值不存在,会在该值应该插入的位置加间隙锁
  • 对索引列进行范围查询时,会在范围的边界加间隙锁
  • 目的:防止幻读(阻止其他事务在间隙中INSERT)

6.5.2 死锁排查

sql 复制代码
-- 查看当前锁等待
SELECT * FROM information_schema.INNODB_TRX;

-- 查看锁等待关系
SELECT * FROM information_schema.INNODB_LOCK_WAITS;

-- 查看当前持有的锁
SELECT * FROM information_schema.INNODB_LOCKS;

-- 查看最近一次死锁信息
SHOW ENGINE INNODB STATUS\G
-- 搜索 "LATEST DETECTED DEADLOCK" 部分

-- 查看当前所有连接
SHOW PROCESSLIST;

-- 杀掉指定连接
KILL <connection_id>;

避免死锁的实践

  1. 不同事务按相同顺序访问表和行
  2. 事务尽量简短(减少持有锁的时间)
  3. 合理使用索引(避免锁升级为表锁)
  4. 大事务拆分为小事务

第7章:存储引擎、日志系统与性能优化基础

7.1 存储引擎概述

存储引擎是MySQL的插件式数据存储层,决定了表的存储方式、是否支持事务、锁粒度等。InnoDB自MySQL 5.5起成为默认引擎

sql 复制代码
-- 查看支持的引擎
SHOW ENGINES;

-- 查看某张表使用的引擎
SHOW TABLE STATUS LIKE 'student';

-- 修改表的引擎
ALTER TABLE student ENGINE=MyISAM;

7.2 InnoDB vs MyISAM

【面试必问】

特性 InnoDB MyISAM
事务 ✅ 支持(ACID) ❌ 不支持
锁粒度 行级锁 表级锁
外键 ✅ 支持 ❌ 不支持
崩溃恢复 ✅ Redo Log自动恢复 ⚠️ 可能损坏,需手动修复
MVCC ✅ 支持高并发读写 ❌ 写操作阻塞所有读
全文索引 MySQL 5.6+ 支持 ✅ 原生支持
数据存储 共享表空间(ibdata1)或独立表空间(.ibd) .MYD(数据) + .MYI(索引)
行数统计 需全表扫描COUNT(*) 有计数器,即时返回
适用场景 需要事务、高并发、崩溃恢复的生产环境 只读/极少写的日志表、数据仓库

为什么MySQL 8.0彻底淘汰MyISAM:MyISAM不支持事务,崩溃后数据可能损坏且无法自动恢复。所有生产场景都应使用InnoDB(MySQL 8.0中系统表也已全部转为InnoDB)。

7.3 InnoDB内存结构

【面试必问】

内存区域 大小参数 作用
Buffer Pool innodb_buffer_pool_size 缓存数据页和索引页,InnoDB最重要的内存区域,建议设为物理内存的50%-70%
Change Buffer innodb_change_buffer_max_size 缓存对二级索引的修改,延迟合并写入
Adaptive Hash Index 自动 对热点数据页自动建Hash索引,加速等值查询
Log Buffer innodb_log_buffer_size Redo Log的内存缓冲区,默认16MB

为什么Buffer Pool设太大也不好 :过大导致OS可用内存不足,可能触发SWAP,性能断崖式下降。生产环境建议:innodb_buffer_pool_size = 物理内存 × 0.6,并监控 SHOW ENGINE INNODB STATUS 中的 Buffer Pool 命中率(应 > 99%)。

7.4 Redo Log(重做日志)

【面试必问】

Redo Log是InnoDB实现**持久性(Durability)**的关键。记录的是"对数据页做了什么物理修改"。

复制代码
写数据流程:
1. 修改Buffer Pool中的数据页
2. 写入Log Buffer(内存 → Redo Log Buffer)
3. 事务提交时:Redo Log Buffer → OS Cache → 磁盘(受innodb_flush_log_at_trx_commit控制)
4. 后台线程定期将Buffer Pool中的脏页刷回数据文件(Checkpoint)

WAL(Write-Ahead Logging):先写日志,后写数据。即使数据库崩溃,重启后通过Redo Log重放已提交但未写入数据文件的事务,保证数据不丢。

Redo Log vs Binlog

维度 Redo Log Binlog
所属 InnoDB引擎层 MySQL Server层
内容 物理日志(数据页修改) 逻辑日志(SQL语句/行变更)
写入方式 循环写入(ib_logfile0/1两个文件轮回) 追加写入(可生成多个文件)
用途 崩溃恢复(Crash Recovery) 主从复制、时间点恢复
大小 固定(默认2×48MB) 可配(max_binlog_size)

【面试必问】两阶段提交(Two-Phase Commit):Redo Log和Binlog的一致性由两阶段提交保证:

  1. Prepare阶段:写入Redo Log(标记为prepare状态)
  2. Commit阶段:写入Binlog → 将Redo Log标记为commit

崩溃恢复时:如果Redo Log是prepare状态但Binlog中没有对应记录,事务回滚;如果Binlog中有记录,事务提交。这保证了主从数据一致。

7.5 Undo Log(回滚日志)

Undo Log记录的是"数据修改前的版本",用于事务回滚和MVCC。

  • 回滚:执行ROLLBACK时,用Undo Log中的旧值覆盖
  • MVCC:其他事务读数据时,通过Undo Log找到可见的历史版本
  • Undo Log也记录Redo Log(Undo的修改也需要持久化)

7.6 慢查询日志与SQL优化

配置慢查询日志

sql 复制代码
-- 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 动态开启(重启失效)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2;  -- 超过2秒记录
ini 复制代码
# my.cnf 永久配置
slow_query_log = ON
slow_query_log_file = /var/log/mysql-slow.log
long_query_time = 2
log_queries_not_using_indexes = ON  # 记录未使用索引的查询

分析慢查询

bash 复制代码
# mysqldumpslow 分析
# 按查询时间排序,取前10条
mysqldumpslow -s t -t 10 /var/log/mysql-slow.log

# 按返回行数排序
mysqldumpslow -s r -t 10 /var/log/mysql-slow.log

# 按出现次数排序
mysqldumpslow -s c -t 10 /var/log/mysql-slow.log

SQL优化思路

sql 复制代码
-- 1. 先用EXPLAIN看执行计划
EXPLAIN SELECT * FROM student WHERE name = '张三';

-- 2. 查看实际执行成本
EXPLAIN FORMAT=JSON SELECT * FROM student WHERE name = '张三';

-- 3. 看是否使用了索引、type是否为ALL
-- 4. 检查Extra是否有 Using filesort / Using temporary

-- 5. 查看索引使用情况
SELECT * FROM sys.schema_unused_indexes;      -- 未使用的索引(建议删除)
SELECT * FROM sys.schema_redundant_indexes;   -- 冗余索引

通用SQL优化原则

  1. 最左匹配:联合索引必须从最左列开始匹配
  2. 避免SELECT *:只查需要的列,争取覆盖索引
  3. 小表驱动大表:JOIN时把小结果集放在前面(驱动表)
  4. 避免前导通配符LIKE '%abc' 不走索引
  5. 用UNION ALL代替OR(非索引列场景)
  6. LIMIT分页优化 :大偏移量时用 WHERE id > last_id LIMIT n 代替 LIMIT m, n

7.7 性能监控命令

sql 复制代码
-- MySQL 运行状态概览
SHOW GLOBAL STATUS;

-- 关键指标
SHOW GLOBAL STATUS LIKE 'Threads_connected';  -- 当前连接数
SHOW GLOBAL STATUS LIKE 'Threads_running';    -- 活跃连接数
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';  -- 逻辑读
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';  -- 物理读(从磁盘读)
-- 缓冲池命中率 = (Read_requests - Reads) / Read_requests (应 > 99%)

SHOW GLOBAL STATUS LIKE 'Innodb_rows_deleted';
SHOW GLOBAL STATUS LIKE 'Innodb_rows_inserted';
SHOW GLOBAL STATUS LIKE 'Innodb_rows_read';
SHOW GLOBAL STATUS LIKE 'Innodb_rows_updated';

-- QPS / TPS 估算(需两次采样计算差值)
-- QPS ≈ (Questions差值) / 时间间隔
-- TPS ≈ (Com_commit + Com_rollback 差值) / 时间间隔

第8章:主从复制与MaxScale读写分离

8.1 主从复制原理

【面试必问】主从复制完整流程

复制代码
Master(主库)                             Slave(从库)
  │                                           │
  │  ① 数据变更写入 binlog                      │
  ├─ binlog ──────────────────────────────►    │
  │                                           │  ② IO线程拉取binlog
  │                                           │     写入relay log
  │                                           │
  │                                           │  ③ SQL线程读取relay log
  │                                           │     重放SQL到从库

四步详解

  1. Master 将数据变更写入 binlog(二进制日志)
  2. Slave IO线程 连接到Master,从指定位置开始拉取binlog,写入本地的 relay log(中继日志)
  3. Slave SQL线程 读取relay log中的事件,在从库上重放执行
  4. 复制持续进行,IO线程和SQL线程各有一个独立的状态

8.2 主从复制配置

四要素

  • 机器:Master (192.168.100.165) + Slave (192.168.100.166)
  • 做什么:搭建MySQL异步主从复制
  • 完整命令:如下
  • 为什么:实现读写分离(读写压力分散)、数据备份(从库可做备份)、高可用基础

环境准备

bash 复制代码
# === 两台机器都执行 ===
# 1. 时间同步(chrony)
systemctl enable --now chronyd

# 2. 关闭防火墙/SELinux(或开放3306端口)
systemctl stop firewalld; systemctl disable firewalld
setenforce 0
# 永久关闭:编辑 /etc/selinux/config → SELINUX=disabled

Master配置(192.168.100.165)

bash 复制代码
# 编辑 /etc/my.cnf,[mysqld] 段添加:
cat >> /etc/my.cnf << 'EOF'
[mysqld]
server-id=1
log-bin=mysql-bin
binlog_format=ROW
log-slave-updates=ON        # 启用后从库的更新也写binlog(级联复制需要)
expire_logs_days=7
EOF

systemctl restart mysqld
sql 复制代码
-- Master创建复制专用用户
CREATE USER 'repl'@'192.168.100.%' IDENTIFIED WITH mysql_native_password BY 'ReplP@ss123';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.100.%';
FLUSH PRIVILEGES;

-- 查看Master状态(记录 File 和 Position,Slave配置时需要)
SHOW MASTER STATUS;
-- +------------------+----------+
-- | File             | Position |
-- +------------------+----------+
-- | mysql-bin.000001 |      856 |
-- +------------------+----------+

Slave配置(192.168.100.166)

bash 复制代码
# 编辑 /etc/my.cnf,[mysqld] 段添加:
[mysqld]
server-id=2
relay-log=relay-log-bin          # 中继日志前缀
relay-log-index=relay-log-bin.index
read_only=ON                      # 从库只读(root和复制线程不受限制)
sql 复制代码
-- 在Slave上执行配置复制
CHANGE MASTER TO
    MASTER_HOST='192.168.100.165',
    MASTER_USER='repl',
    MASTER_PASSWORD='ReplP@ss123',
    MASTER_LOG_FILE='mysql-bin.000001',   -- 来自 SHOW MASTER STATUS
    MASTER_LOG_POS=856;                    -- 来自 SHOW MASTER STATUS

-- 启动复制
START SLAVE;

-- 查看复制状态(\G 纵向显示)
SHOW SLAVE STATUS\G

关键状态字段

sql 复制代码
SHOW SLAVE STATUS\G
字段 期望值 非正常状态原因
Slave_IO_Running Yes Connecting→网络不通、用户名密码错误、防火墙
Slave_SQL_Running Yes No→relay log重放出错(主键冲突/表不存在等)
Seconds_Behind_Master 0或接近0 延迟过大→大事务、SQL线程单线程瓶颈
Master_Log_File 当前binlog文件 ---
Read_Master_Log_Pos 当前读取位置 ---
Relay_Log_File 当前relay log ---
Last_IO_Errno 0 非0→查看Last_IO_Error
Last_SQL_Errno 0 非0→查看Last_SQL_Error

8.3 复制常见问题与修复

IO线程连接失败

bash 复制代码
# 错误:Last_IO_Errno: 2003 - Can't connect to MySQL server
# 原因:网络不通或防火墙
# 排查:
ping 192.168.100.165
telnet 192.168.100.165 3306

# 错误:Last_IO_Errno: 1045 - Access denied
# 原因:复制用户密码错误或权限不足
# 解决:在Master重新创建用户并授权

SQL线程出错

bash 复制代码
# 常见错误:主键冲突(Slave上有重复数据)
# 解决:
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;  -- 跳过一个事件
START SLAVE;

# 更安全的做法(MySQL 8.0.26+)
STOP SLAVE;
CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='...', SOURCE_LOG_POS=...;
START SLAVE;

复制延迟排查

sql 复制代码
-- 查看延迟
SHOW SLAVE STATUS\G  -- 看 Seconds_Behind_Master

-- 原因分析:
-- 1. 大事务(一次性更新百万行)
-- 2. Slave硬件性能低于Master
-- 3. SQL线程单线程瓶颈(MySQL 5.6并行复制可缓解)
-- 4. 锁等待

-- 并行复制配置(MySQL 5.7+)
SET GLOBAL slave_parallel_type = LOGICAL_CLOCK;
SET GLOBAL slave_parallel_workers = 4;

8.4 半同步复制

【知识拓展】 默认复制是异步的,Master提交事务后不等待Slave确认。半同步复制保证至少一个Slave收到binlog后才返回客户端。

sql 复制代码
-- Master安装插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

-- Slave安装插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

-- 启用
SET GLOBAL rpl_semi_sync_master_enabled = ON;
SET GLOBAL rpl_semi_sync_slave_enabled = ON;

-- 查看状态
SHOW STATUS LIKE 'Rpl_semi_sync%';

8.5 MaxScale读写分离

【教案补充】 MaxScale是MariaDB开发的数据库代理,实现读写分离和负载均衡。

四要素

  • 机器:MaxScale代理服务器(192.168.100.170)
  • 做什么:部署MaxScale实现对MySQL主从集群的读写分离
  • 完整命令:如下
  • 为什么:应用层不需要关心读写路由,MaxScale自动分离读写请求,写走Master、读走Slave

安装MaxScale

bash 复制代码
# OpenEuler 24.03 / CentOS 8+
dnf install -y maxscale

# 创建监控用户(在Master上执行)
# mysql -uroot -p
# CREATE USER 'maxmon'@'192.168.100.%' IDENTIFIED BY 'MonitorP@ss';
# GRANT SELECT ON mysql.* TO 'maxmon'@'192.168.100.%';
# GRANT SHOW DATABASES ON *.* TO 'maxmon'@'192.168.100.%';

配置MaxScale

bash 复制代码
# 编辑 /etc/maxscale.cnf
cat > /etc/maxscale.cnf << 'EOF'
[maxscale]
threads=auto

# 定义Master服务器
[master-server]
type=server
address=192.168.100.165
port=3306
protocol=MariaDBBackend

# 定义Slave服务器
[slave-server]
type=server
address=192.168.100.166
port=3306
protocol=MariaDBBackend

# 监控模块
[MySQL-Monitor]
type=monitor
module=mariadbmon
servers=master-server,slave-server
user=maxmon
password=MonitorP@ss
monitor_interval=2000

# 读写分离路由
[Read-Write-Service]
type=service
router=readwritesplit
servers=master-server,slave-server
user=maxmon
password=MonitorP@ss

# 监听端口
[Read-Write-Listener]
type=listener
service=Read-Write-Service
protocol=MariaDBClient
port=3306
EOF

systemctl enable --now maxscale

验证读写分离

bash 复制代码
# 连接MaxScale(3306端口)
mysql -h 192.168.100.170 -u appuser -p -P 3306

# 写操作:自动路由到Master
INSERT INTO student(name) VALUES('maxscale测试');

# 读操作:自动路由到Slave
SELECT * FROM student;

readwritesplit工作原理

  • SELECT 开头的语句 → 路由到Slave
  • INSERT/UPDATE/DELETE/CREATE/ALTER/... → 路由到Master
  • 事务中的语句(BEGIN...COMMIT)→ 全部路由到Master
  • FOR UPDATE / LOCK IN SHARE MODE 的SELECT → 路由到Master

第9章:MySQL高可用架构(Galera Cluster / MGR / TLS加密)

9.1 高可用架构概述

生产环境不能依赖单点MySQL,高可用(High Availability, HA)确保单节点故障时服务不中断。

架构 原理 一致性 多主写入 复杂度 适用
主从+手动切换 binlog异步复制 开发/测试
MHA 故障自动检测+切换 互联网通用
Galera Cluster 同步复制(wsrep) 国产生态/需要多主
组复制MGR Paxos协议 可选 金融级一致性
Orchestrator + VIP 自动故障切换 弱/半同步 大型互联网

9.2 Galera Cluster

【面试必问】Galera vs 主从复制

维度 传统主从 Galera Cluster
复制方式 binlog异步/半同步 wsrep同步复制(基于写集)
主从关系 Master-Slave(单向) 多主(Multi-Master),任意节点可读写
数据一致性 可能不一致 强一致性(所有节点确认后才提交)
故障切换 需手动+MHA 自动,无单点故障
扩容 增加Slave 添加节点,自动同步
适用场景 读写分离、备份 多活、跨机房、需要多主写入

Galera原理(wsrep API):事务在本地执行后,将"写集"(Write Set)广播给集群中所有节点,每个节点验证并应用。只有所有节点确认后事务才提交(基于全局事务ID的certification机制)。

Galera Cluster部署

四要素

  • 机器:3台(最少)--- node1: 192.168.100.165 / node2: 192.168.100.166 / node3: 192.168.100.167
  • 做什么:部署Galera Cluster多主MySQL集群
  • 完整命令:如下
  • 为什么:实现多主写入、自动故障切换、强一致性
bash 复制代码
# === 三台机器都执行 ===
# 环境准备
systemctl stop firewalld; systemctl disable firewalld
setenforce 0
systemctl stop mysqld  # 如果已有MySQL

# 安装 Galera(以MariaDB Galera为例)
dnf install -y mariadb-server-galera

# 编辑配置文件 /etc/my.cnf.d/galera.cnf
cat > /etc/my.cnf.d/galera.cnf << 'EOF'
[mysqld]
bind-address=0.0.0.0

# Galera Provider
wsrep_on=ON
wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so

# 集群配置
wsrep_cluster_name="my_galera_cluster"
wsrep_cluster_address="gcomm://192.168.100.165,192.168.100.166,192.168.100.167"

# 节点信息(每个节点不同:node1=165, node2=166, node3=167)
wsrep_node_name="node1"
wsrep_node_address="192.168.100.165"

# 复制设置
binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
innodb_flush_log_at_trx_commit=2
EOF

# === 首次启动(仅在node1执行)===
galera_new_cluster

# === 其他节点启动 ===
systemctl start mariadb

# === 验证集群 ===
mysql -uroot -p -e "SHOW STATUS LIKE 'wsrep_cluster_size';"
# wsrep_cluster_size: 3  -- 集群节点数

mysql -uroot -p -e "SHOW STATUS LIKE 'wsrep_ready';"
# wsrep_ready: ON  -- 集群就绪

mysql -uroot -p -e "SHOW STATUS LIKE 'wsrep_%';"

关键wsrep状态变量

变量 含义
wsrep_cluster_size 集群中的节点数
wsrep_ready 节点是否就绪
wsrep_connected 是否连接到集群
wsrep_local_state_comment 节点状态(Synced/Donor/Joining)
wsrep_flow_control_paused 流控暂停时间(应接近0)

Galera注意事项

  1. 仅支持InnoDB引擎(MyISAM表无法同步)
  2. 所有表必须有主键(没有主键会导致DELETE出错)
  3. 不支持LOCK TABLES / GET_LOCK()
  4. 大事务影响性能(写集需要在所有节点验证)
  5. 最少3节点(2节点有脑裂风险)

9.3 MySQL组复制(MGR)

【知识拓展】 MySQL Group Replication(MGR)是MySQL 5.7.17+内置的高可用方案,基于Paxos协议实现。

模式 写入 故障切换
单主模式 只有Primary可写,其他只读 Primary故障自动选新Primary
多主模式 所有节点可写 任意节点故障不影响集群
sql 复制代码
-- MGR搭建关键步骤(3节点)

-- 1. 安装组复制插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so';

-- 2. 配置my.cnf(关键参数)
-- loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
-- loose-group_replication_local_address="192.168.100.165:33061"
-- loose-group_replication_group_seeds="192.168.100.165:33061,192.168.100.166:33061,192.168.100.167:33061"
-- loose-group_replication_bootstrap_group=OFF
-- loose-group_replication_single_primary_mode=ON

-- 3. 创建复制用户 + 设置通道
-- CHANGE MASTER TO ... FOR CHANNEL 'group_replication_recovery';

-- 4. 启动组复制(首个节点需bootstrap)
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;

-- 其他节点
START GROUP_REPLICATION;

-- 查看集群状态
SELECT * FROM performance_schema.replication_group_members;

9.4 MySQL TLS加密配置

四要素

  • 机器:MySQL服务器
  • 做什么:配置MySQL TLS加密,强制所有连接使用SSL
  • 完整命令:如下
  • 为什么:防止数据在网络传输中被窃听,是安全合规的必备措施

生成证书

bash 复制代码
# 1. 生成CA私钥和证书
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -days 3650 -key ca-key.pem -out ca-cert.pem \
    -subj "/CN=MySQL_CA"

# 2. 生成服务端私钥和证书
openssl req -newkey rsa:2048 -days 3650 -nodes \
    -keyout server-key.pem -out server-req.pem \
    -subj "/CN=mysql-server"
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -days 3650 -in server-req.pem \
    -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial \
    -out server-cert.pem

# 3. 生成客户端私钥和证书
openssl req -newkey rsa:2048 -days 3650 -nodes \
    -keyout client-key.pem -out client-req.pem \
    -subj "/CN=mysql-client"
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -days 3650 -in client-req.pem \
    -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial \
    -out client-cert.pem

# 4. 部署证书到MySQL数据目录
cp ca-cert.pem server-cert.pem server-key.pem /var/lib/mysql/
chown mysql:mysql /var/lib/mysql/*.pem
chmod 600 /var/lib/mysql/*.pem

配置MySQL启用SSL

ini 复制代码
# my.cnf
[mysqld]
ssl-ca=/var/lib/mysql/ca-cert.pem
ssl-cert=/var/lib/mysql/server-cert.pem
ssl-key=/var/lib/mysql/server-key.pem
sql 复制代码
-- 重启后验证SSL是否启用
SHOW VARIABLES LIKE '%ssl%';
-- have_ssl: YES

-- 创建必须使用SSL连接的用户
CREATE USER 'secure_user'@'%' IDENTIFIED BY 'StrongP@ss' REQUIRE SSL;

-- 创建使用X509证书认证的用户
CREATE USER 'cert_user'@'%' IDENTIFIED BY 'StrongP@ss' REQUIRE X509;

客户端SSL连接

bash 复制代码
# 客户端使用SSL连接
mysql -h 192.168.100.165 -u secure_user -p \
    --ssl-ca=client-cert.pem \
    --ssl-cert=client-cert.pem \
    --ssl-key=client-key.pem

# 验证当前连接是否使用SSL
mysql> \s
# SSL: Cipher in use is TLS_AES_256_GCM_SHA384

# 或
mysql> SHOW STATUS LIKE 'Ssl_cipher';

第10章:分库分表策略、大表DDL、故障排查与安全加固

10.1 分库分表概述

当单表数据量突破千万级或单库无法承载写入压力时,需要对数据进行拆分。

拆分方式

维度 垂直拆分 水平拆分
操作 按业务模块拆库/按字段拆分表 按行拆分到多个库/表
示例 用户库、订单库、商品库独立 user_0, user_1, user_2... user_1023
解决问题 单库压力大、业务耦合 单表数据量过大、写入瓶颈
实现方式 应用层路由 MyCat/ShardingSphere中间件

【面试必问】分库分表后面临的挑战

挑战 解决方案
跨库Join 应用层聚合(多次查询+代码合并)或冗余字段设计
分布式事务 XA协议 / TCC / 最终一致性 + 消息队列
全局唯一ID 雪花算法(Snowflake)/ 号段模式 / Redis自增
分片键选择 选择查询中最常带的条件作为分片键,避免跨片查询
扩容迁移 一致性Hash / 双写+灰度迁移

10.2 MyCat中间件分片

【教案补充】 MyCat是开源的数据库中间件,实现分库分表和读写分离。

MyCat核心配置

xml 复制代码
<!-- schema.xml -->
<schema name="order_db" checkSQLschema="false" sqlMaxLimit="100">
    <!-- 分片表:按user_id取模分片 -->
    <table name="t_order" dataNode="dn1,dn2" rule="mod-long" />
</schema>

<dataNode name="dn1" dataHost="host1" database="order_db_0" />
<dataNode name="dn2" dataHost="host2" database="order_db_1" />

<dataHost name="host1" maxCon="100" minCon="10" balance="0">
    <writeHost host="master1" url="192.168.100.165:3306" user="mycat" password="xxx" />
</dataHost>
xml 复制代码
<!-- rule.xml 分片规则 -->
<tableRule name="mod-long">
    <rule>
        <columns>user_id</columns>
        <algorithm>mod-long</algorithm>
    </rule>
</tableRule>

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    <property name="count">2</property>  <!-- 2个分片 -->
</function>

分布式事务---XA协议

sql 复制代码
-- XA事务示例(两阶段提交 2PC)
XA START 'xid1';
INSERT INTO order_db_0.t_order VALUES(...);
XA END 'xid1';
XA PREPARE 'xid1';

XA START 'xid2';
INSERT INTO order_db_1.t_order VALUES(...);
XA END 'xid2';
XA PREPARE 'xid2';

-- 第一阶段全部成功 → 第二阶段提交
XA COMMIT 'xid1';
XA COMMIT 'xid2';

XA的局限性:性能开销大(需要多次网络通信)、单点故障(协调者故障时参与者可能阻塞)。

10.3 大表DDL修改

【面试必问】 直接对亿级数据的大表执行 ALTER TABLE ... ADD COLUMN 会锁表(取决于操作类型),导致业务阻塞。

DDL类型与锁行为

操作 早期MySQL MySQL 5.6+ Online DDL 8.0 原子DDL
ADD COLUMN 锁表 不锁(允许并发DML) 不锁+原子
ADD INDEX 锁表 不锁 不锁+原子
MODIFY COLUMN(改类型) 锁表 锁表(需重建) 锁表+原子
DROP COLUMN 锁表 不锁(仅改元数据) 不锁+原子

pt-online-schema-change

对于不支持Online DDL的操作(如修改列类型),使用Percona Toolkit的 pt-online-schema-change(pt-osc):

bash 复制代码
# 安装 Percona Toolkit
dnf install -y percona-toolkit

# pt-osc 原理:创建新表 → 逐批复制数据 → 原子切换
pt-online-schema-change \
    --user=root --password='xxx' \
    --alter "MODIFY COLUMN content TEXT" \
    D=school,t=articles \
    --execute

pt-osc原理

  1. 创建一张与原表结构相同的新表(含修改后的列定义)
  2. 在原表上创建触发器(INSERT/UPDATE/DELETE),确保新写入不丢失
  3. 分批次(chunk)将原表数据复制到新表
  4. 复制完成后,原子性地执行 RENAME TABLE 交换新旧表
  5. 删除旧表和触发器

注意事项:需要有足够的磁盘空间(约原表大小的2倍)、原表必须有主键或唯一索引、操作期间不能对原表执行DDL。

10.4 MySQL故障排查

【教案补充】 常见MySQL故障类型及排查命令。

十大故障类型

故障类型 常见现象 排查命令
1. 连接故障 Too many connections SHOW PROCESSLIST; SHOW VARIABLES LIKE 'max_connections';
2. 性能故障 查询慢、CPU高 SHOW PROCESSLIST; EXPLAIN 慢查询 top/htop
3. 复制故障 Slave延迟/报错 SHOW SLAVE STATUS\G
4. 数据恢复故障 binlog找不到 SHOW MASTER STATUS; SHOW BINARY LOGS;
5. 高可用故障 集群脑裂 wsrep_cluster_status replication_group_members
6. 存储引擎故障 表损坏 CHECK TABLE xxx; REPAIR TABLE xxx;(MyISAM)
7. 内存故障 OOM、SWAP free -h SHOW ENGINE INNODB STATUS\G
8. 安全故障 暴力破解 grep 'Access denied' /var/log/mysqld.log
9. 备份故障 备份失败/恢复失败 xtrabackup日志、mysqldump错误输出
10. 升级故障 升级后无法启动 错误日志 /var/log/mysqld.log

通用排查流程

bash 复制代码
# 1. 查看错误日志(第一优先)
tail -100 /var/log/mysqld.log

# 2. 查看当前连接
mysql -uroot -p -e "SHOW PROCESSLIST;"

# 3. 查看锁等待
mysql -uroot -p -e "SELECT * FROM information_schema.INNODB_TRX;"

# 4. 查看服务状态
systemctl status mysqld

# 5. 查看系统资源
top -bn1 | head -20
df -h           # 磁盘空间
free -h         # 内存
iostat -x 1 3   # 磁盘IO

常见故障解决方案

sql 复制代码
-- 连接数满
SET GLOBAL max_connections = 1000;

-- 杀掉长时间运行的查询
SELECT CONCAT('KILL ', id, ';') FROM information_schema.PROCESSLIST
WHERE time > 60 AND command != 'Sleep';

-- 跳过复制错误
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE;

-- 表损坏修复(MyISAM)
REPAIR TABLE table_name;

10.5 MySQL安全加固

【教案补充】安全基线检查清单

认证安全

  • 移除匿名用户:DELETE FROM mysql.user WHERE user='';

  • 删除test数据库:DROP DATABASE IF EXISTS test;

  • 禁止root远程登录:DELETE FROM mysql.user WHERE user='root' AND host!='localhost';

  • 强制使用强密码策略:

    sql 复制代码
    SET GLOBAL validate_password.length=12;
    SET GLOBAL validate_password.mixed_case_count=1;
    SET GLOBAL validate_password.number_count=1;
    SET GLOBAL validate_password.special_char_count=1;

网络安全

  • 绑定本地IP:bind-address = 192.168.100.165
  • 修改默认端口(可选):port = 3307
  • 限制单用户连接数:max_user_connections = 50
  • 启用防火墙只开放必要IP访问3306

数据安全

  • 启用TLS加密传输(见第9章)
  • local_infile = OFF(禁止LOAD DATA LOCAL)
  • secure_file_priv = /backup(限制文件读写目录)
  • binlog加密(MySQL 8.0.14+):binlog_encryption = ON

审计与日志

  • 开启错误日志:log_error = /var/log/mysqld.log
  • 开启慢查询日志
  • 开启通用查询日志(仅在排查时,平时关闭):general_log = OFF
  • 定期审计用户权限:SELECT * FROM mysql.user;

10.6 灾难恢复流程

复制代码
灾难发生
  │
  ├─ 1. 止损:断开问题节点/切换备用节点
  │
  ├─ 2. 评估:确认数据损坏范围和时间点
  │
  ├─ 3. 恢复:
  │     ├─ 有XtraBackup → 恢复最近全量 → 合并增量 → 应用binlog到指定时间点
  │     └─ 无XtraBackup → mysqldump恢复 → 应用binlog
  │
  ├─ 4. 验证:检查关键表数据完整性、行数
  │
  └─ 5. 回归:切换流量回原节点/新节点,监控运行
bash 复制代码
# 完整恢复命令示例
# 恢复全量
xtrabackup --copy-back --target-dir=/backup/full_20260607
# 恢复增量
xtrabackup --prepare --target-dir=/backup/full_20260607 --incremental-dir=/backup/inc_20260607_12
# 应用binlog到误操作前一刻
mysqlbinlog --stop-datetime="2026-06-07 14:30:00" mysql-bin.000010 | mysql -uroot -p
# 启动MySQL
systemctl start mysqld

附录A:面试必问知识点速查

排序 知识点 章节 考察频率
1 B+Tree索引原理、最左匹配、索引失效 第5章 11.18%
2 SQL优化、EXPLAIN执行计划 第5/7章 6.20%
3 事务ACID与四种隔离级别 第6章 3.55%
4 InnoDB vs MyISAM 第7章 2.73%
5 MVCC原理(Undo Log + Read View) 第6章 1.97%
6 锁机制(行锁/间隙锁/死锁) 第6章 1.67%
7 主从复制原理与状态 第8章 高频
8 Redo Log vs Binlog、两阶段提交 第7章 高频
9 分库分表策略与挑战 第10章 中频
10 Galera vs MGR高可用对比 第9章 中频

附录B:MySQL DBA学习路径

阶段 内容 来源
初级 SQL语言、数据类型、库表操作、用户权限 第1-3章
中级 索引优化、事务锁、备份恢复、主从复制 第4-8章
高级 高可用(Galera/MGR)、分库分表、性能调优、故障排查、安全加固 第9-10章
专家 内核源码、InnoDB存储引擎深度、分布式数据库、全链路压测 进阶路线
相关推荐
sweetone1 小时前
SONY老式磁带随身听wm-fx193 之摩机过程(提升重低音音效,改耳放)
经验分享·音视频
健康平安的活着1 小时前
mysql中数据库脚本太大,通过脚本命令修改db名称
数据库·mysql
数据法师2 小时前
视频文件重复检测工具:基于哈希与视频指纹的三级筛选机制
算法·音视频·哈希算法
GHL2842710902 小时前
PowerShell快捷键学习
学习
AI创界者2 小时前
告别云端限制!Sulphur 2 本地文生视频/图生视频整合包,本地部署,解压即用,保姆级部署与工作流实战
人工智能·python·aigc·音视频
半导体守望者3 小时前
AE电源闭环控制——反应溅射的集成解决方案
经验分享·学习·机器人·自动化·制造
minji...3 小时前
MySQL数据库 (八) MySQL表的基本查询(下),truncate、group by、聚合函数、分组聚合统计
数据库·mysql·聚合函数·update·分组聚合统计
乐世东方客3 小时前
备份脚本记录(binlog文件+mysql+mongo)
android·数据库·mysql
暴力求解3 小时前
MySQL---数据类型
数据库·mysql
小饕3 小时前
RAG学习之【向量数据库】Milvus 从入门到精通:索引、检索、混合搜索一篇打通(RAG 必备)
数据库·人工智能·学习·milvus