MySQL5.7生产运维手册

MySQL 5.7 生产运维手册

面向生产环境的 MySQL 5.7 安装、配置、SQL、备份恢复、主从复制、性能调优与故障排障指南

适用场景:业务 OLTP、读写分离、分库分表前置、日常 DBA 运维

版本说明:本文针对 MySQL 5.7.x (5.7 无 CTE/窗口函数,见 附录


目录

  1. 架构与核心原理
  2. 安装部署与目录规划
  3. 核心配置参数
  4. 用户权限与安全
  5. [SQL 基础与数据类型](#SQL 基础与数据类型)
  6. [SQL 组合查询与实战](#SQL 组合查询与实战)
  7. 索引与执行计划
  8. 事务、锁与死锁
  9. 备份与恢复
  10. 主从复制与高可用
    • [10.6 通过 xtrabackup 备份恢复搭建主从](#10.6 通过 xtrabackup 备份恢复搭建主从)
    • [10.7 MHA 高可用启停](#10.7 MHA 高可用启停)
  11. 性能监控与慢查询
  12. 性能调优
  13. 日常运维命令
  14. 故障排查手册
  15. [故障处理 SOP](#故障处理 SOP)
  16. 日常巡检清单
  17. 值班速查
  18. [在线 DDL 与 gh-ost](#在线 DDL 与 gh-ost)

1. 架构与核心原理

1.1 MySQL 逻辑架构

#mermaid-svg-jMpN0W4Ug6EAJww8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jMpN0W4Ug6EAJww8 .error-icon{fill:#552222;}#mermaid-svg-jMpN0W4Ug6EAJww8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jMpN0W4Ug6EAJww8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .marker.cross{stroke:#333333;}#mermaid-svg-jMpN0W4Ug6EAJww8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jMpN0W4Ug6EAJww8 p{margin:0;}#mermaid-svg-jMpN0W4Ug6EAJww8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .cluster-label text{fill:#333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .cluster-label span{color:#333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .cluster-label span p{background-color:transparent;}#mermaid-svg-jMpN0W4Ug6EAJww8 .label text,#mermaid-svg-jMpN0W4Ug6EAJww8 span{fill:#333;color:#333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .node rect,#mermaid-svg-jMpN0W4Ug6EAJww8 .node circle,#mermaid-svg-jMpN0W4Ug6EAJww8 .node ellipse,#mermaid-svg-jMpN0W4Ug6EAJww8 .node polygon,#mermaid-svg-jMpN0W4Ug6EAJww8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jMpN0W4Ug6EAJww8 .rough-node .label text,#mermaid-svg-jMpN0W4Ug6EAJww8 .node .label text,#mermaid-svg-jMpN0W4Ug6EAJww8 .image-shape .label,#mermaid-svg-jMpN0W4Ug6EAJww8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-jMpN0W4Ug6EAJww8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jMpN0W4Ug6EAJww8 .rough-node .label,#mermaid-svg-jMpN0W4Ug6EAJww8 .node .label,#mermaid-svg-jMpN0W4Ug6EAJww8 .image-shape .label,#mermaid-svg-jMpN0W4Ug6EAJww8 .icon-shape .label{text-align:center;}#mermaid-svg-jMpN0W4Ug6EAJww8 .node.clickable{cursor:pointer;}#mermaid-svg-jMpN0W4Ug6EAJww8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .arrowheadPath{fill:#333333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jMpN0W4Ug6EAJww8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jMpN0W4Ug6EAJww8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jMpN0W4Ug6EAJww8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jMpN0W4Ug6EAJww8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jMpN0W4Ug6EAJww8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jMpN0W4Ug6EAJww8 .cluster text{fill:#333;}#mermaid-svg-jMpN0W4Ug6EAJww8 .cluster span{color:#333;}#mermaid-svg-jMpN0W4Ug6EAJww8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jMpN0W4Ug6EAJww8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jMpN0W4Ug6EAJww8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-jMpN0W4Ug6EAJww8 .icon-shape,#mermaid-svg-jMpN0W4Ug6EAJww8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jMpN0W4Ug6EAJww8 .icon-shape p,#mermaid-svg-jMpN0W4Ug6EAJww8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jMpN0W4Ug6EAJww8 .icon-shape .label rect,#mermaid-svg-jMpN0W4Ug6EAJww8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jMpN0W4Ug6EAJww8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jMpN0W4Ug6EAJww8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jMpN0W4Ug6EAJww8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 磁盘
MySQL Server
客户端
存储引擎层
SQL 层
DML
应用 / JDBC / mysql CLI
连接层

认证 / 线程 / 连接池
解析器
优化器
查询缓存 5.7
InnoDB 默认
MyISAM 等
.ibd 数据文件
redo log
undo log
binlog

层次 职责 运维关注
连接层 认证、连接管理、线程分配 max_connections、连接数监控
SQL 层 解析、优化、缓存、权限检查 慢 SQL、执行计划
存储引擎层 数据读写、事务、锁 InnoDB 状态、表空间
文件层 数据文件、日志 磁盘、IO、备份

1.2 InnoDB 核心机制

Buffer Pool(缓冲池)
  • 热点数据页索引页缓存在内存,减少磁盘 IO
  • 默认占物理内存 50%~70%(需给 OS 留余量)
  • 脏页异步刷盘,由 innodb_flush_log_at_trx_commit 和 checkpoint 控制
redo log(重做日志)
  • 物理日志,记录「在某个数据页上做了什么修改」
  • 循环写,固定大小(如 2GB×2 组)
  • 作用:崩溃恢复(Crash Recovery),保证已提交事务持久化
  • 写入顺序:事务修改 → 写 redo log(prepare)→ 写 binlog → redo commit
undo log(回滚日志)
  • 记录数据修改前的旧值
  • 作用:事务回滚MVCC 多版本读(一致性非锁定读)
  • 长事务会导致 undo 堆积,拖慢 purge
binlog(二进制日志)
  • 逻辑日志,记录 SQL 或行变更(ROW/STATEMENT/MIXED)
  • 用于:主从复制点对点恢复
  • 由 Server 层产生,与存储引擎无关
MVCC(多版本并发控制)
  • 每行有隐藏列:DB_TRX_ID(事务 ID)、回滚指针
  • READ COMMITTED:每次读生成新 Read View
  • REPEATABLE READ(InnoDB 默认):事务内第一次读生成 Read View,后续复用
  • 幻读 :RR 下 InnoDB 通过 Next-Key Lock(记录锁 + 间隙锁)缓解

1.3 一条 UPDATE 的完整路径

binlog redo log InnoDB Server/SQL层 Client binlog redo log InnoDB Server/SQL层 Client #mermaid-svg-3tJMhn2w3tIMC0vS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3tJMhn2w3tIMC0vS .error-icon{fill:#552222;}#mermaid-svg-3tJMhn2w3tIMC0vS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3tJMhn2w3tIMC0vS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3tJMhn2w3tIMC0vS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3tJMhn2w3tIMC0vS .marker.cross{stroke:#333333;}#mermaid-svg-3tJMhn2w3tIMC0vS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3tJMhn2w3tIMC0vS p{margin:0;}#mermaid-svg-3tJMhn2w3tIMC0vS .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3tJMhn2w3tIMC0vS text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-3tJMhn2w3tIMC0vS .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-3tJMhn2w3tIMC0vS .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-3tJMhn2w3tIMC0vS .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-3tJMhn2w3tIMC0vS .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-3tJMhn2w3tIMC0vS #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-3tJMhn2w3tIMC0vS .sequenceNumber{fill:white;}#mermaid-svg-3tJMhn2w3tIMC0vS #sequencenumber{fill:#333;}#mermaid-svg-3tJMhn2w3tIMC0vS #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-3tJMhn2w3tIMC0vS .messageText{fill:#333;stroke:none;}#mermaid-svg-3tJMhn2w3tIMC0vS .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3tJMhn2w3tIMC0vS .labelText,#mermaid-svg-3tJMhn2w3tIMC0vS .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-3tJMhn2w3tIMC0vS .loopText,#mermaid-svg-3tJMhn2w3tIMC0vS .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-3tJMhn2w3tIMC0vS .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-3tJMhn2w3tIMC0vS .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-3tJMhn2w3tIMC0vS .noteText,#mermaid-svg-3tJMhn2w3tIMC0vS .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-3tJMhn2w3tIMC0vS .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3tJMhn2w3tIMC0vS .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3tJMhn2w3tIMC0vS .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3tJMhn2w3tIMC0vS .actorPopupMenu{position:absolute;}#mermaid-svg-3tJMhn2w3tIMC0vS .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-3tJMhn2w3tIMC0vS .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3tJMhn2w3tIMC0vS .actor-man circle,#mermaid-svg-3tJMhn2w3tIMC0vS line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-3tJMhn2w3tIMC0vS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 后台线程异步刷脏页到 .ibd UPDATE ... WHERE id=1 打开表、解析条件 加锁、读数据页(Buffer Pool) 写 redo log(prepare) 写 binlog redo commit 修改内存页(脏页) 返回 OK

1.4 表空间与文件

文件/目录 说明
ibdata1 系统表空间(5.7 默认共享;innodb_file_per_table=ON 时每表独立 .ibd
*.ibd 独立表空间数据+索引
ib_logfile* redo log 文件
undo_* undo 表空间(5.7.8+ 可独立)
mysql-bin.* binlog
*.frm 表结构定义(5.7)
slow.log / error.log 慢查询、错误日志

2. 安装部署与目录规划

2.1 生产目录规划

text 复制代码
/data/mysql/
├── data/           # datadir,数据文件
├── logs/
│   ├── error.log
│   ├── slow.log
│   └── mysql-bin.*
├── tmp/            # tmpdir
└── backup/         # 本地备份暂存
/etc/my.cnf         # 主配置

2.2 安装(YUM / 二进制)

bash 复制代码
# CentOS 7 示例
wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
rpm -ivh mysql57-community-release-el7-11.noarch.rpm
yum install -y mysql-community-server-5.7.44

# 初始化(若空数据目录)
mysqld --initialize-insecure --user=mysql --datadir=/data/mysql/data
# 或安全模式(生成临时 root 密码)
mysqld --initialize --user=mysql --datadir=/data/mysql/data

systemctl enable mysqld
systemctl start mysqld
grep 'temporary password' /var/log/mysqld.log   # 首次登录改密

2.3 初始化后必做

sql 复制代码
-- 修改 root 密码(5.7 密码策略较严)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStr0ng#Pass';
-- 或降低策略(仅测试环境)
SET GLOBAL validate_password_policy=LOW;

-- 删除匿名用户、禁止 root 远程(按需)
DELETE FROM mysql.user WHERE User='';
DROP USER IF EXISTS 'root'@'%';   -- 生产建议单独建运维账号
FLUSH PRIVILEGES;

2.4 systemd 管理

bash 复制代码
systemctl status mysqld
systemctl start|stop|restart mysqld
# 改配置后
mysqladmin -uroot -p variables | grep -i config   # 确认生效项
# 动态参数 SET GLOBAL;静态参数需重启

3. 核心配置参数

3.1 my.cnf 生产模板(精简)

ini 复制代码
[mysqld]
user                    = mysql
port                    = 3306
socket                  = /var/lib/mysql/mysql.sock
pid-file                = /var/run/mysqld/mysqld.pid
datadir                 = /data/mysql/data
tmpdir                  = /data/mysql/tmp
log-error               = /data/mysql/logs/error.log
slow_query_log          = 1
slow_query_log_file     = /data/mysql/logs/slow.log
long_query_time         = 1
log_queries_not_using_indexes = 0

# 字符集
character-set-server    = utf8mb4
collation-server        = utf8mb4_unicode_ci

# 连接
max_connections         = 2000
max_connect_errors      = 100000
wait_timeout            = 600
interactive_timeout     = 600
back_log                = 512

# InnoDB
default_storage_engine  = InnoDB
innodb_buffer_pool_size = 16G          # 物理内存 50%~70%
innodb_buffer_pool_instances = 8       # 每实例至少 1GB
innodb_log_file_size    = 2G
innodb_log_buffer_size  = 64M
innodb_flush_log_at_trx_commit = 1     # 1=最安全;2=性能折中
innodb_flush_method     = O_DIRECT
innodb_file_per_table   = 1
innodb_io_capacity      = 2000         # SSD 可调高
innodb_read_io_threads  = 8
innodb_write_io_threads = 8
innodb_lock_wait_timeout = 50

# binlog
server-id               = 1
log_bin                 = /data/mysql/logs/mysql-bin
binlog_format           = ROW          # 主从/恢复推荐 ROW
expire_logs_days        = 7
sync_binlog             = 1            # 1=最安全
max_binlog_size         = 1G
gtid_mode               = ON           # 主从建议开启
enforce_gtid_consistency = ON

# 复制(从库)
# read_only = 1
# super_read_only = 1
# relay_log_recovery = 1

# 安全
local_infile            = 0
symbolic-links          = 0
sql_mode                = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

[client]
default-character-set   = utf8mb4
socket                  = /var/lib/mysql/mysql.sock

3.2 参数速查

参数 含义 生产建议
innodb_buffer_pool_size 缓冲池 内存主力,最重要
innodb_flush_log_at_trx_commit redo 刷盘策略 金融=1;可接受丢 1s=2
sync_binlog binlog 刷盘 主库=1
max_connections 最大连接 配合连接池,避免过大
thread_cache_size 线程缓存 减少建连开销
table_open_cache 表缓存 表多时调大
innodb_lock_wait_timeout 等锁超时 默认 50s,OLTP 可降

4. 用户权限与安全

4.1 账号规范

sql 复制代码
-- 按最小权限:应用只读写业务库
CREATE USER 'app_rw'@'10.%.%.%' IDENTIFIED BY '复杂密码';
GRANT SELECT, INSERT, UPDATE, DELETE ON biz_db.* TO 'app_rw'@'10.%.%.%';

-- 只读从库 / 报表
CREATE USER 'app_ro'@'10.%.%.%' IDENTIFIED BY '复杂密码';
GRANT SELECT ON biz_db.* TO 'app_ro'@'10.%.%.%';

-- 运维备份账号
CREATE USER 'backup'@'localhost' IDENTIFIED BY '复杂密码';
GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'backup'@'localhost';

FLUSH PRIVILEGES;

4.2 权限查看与回收

sql 复制代码
SHOW GRANTS FOR 'app_rw'@'10.%.%.%';
REVOKE DELETE ON biz_db.* FROM 'app_rw'@'10.%.%.%';
DROP USER 'app_rw'@'10.%.%.%';

4.3 安全清单

  • 禁止 root 远程、禁止空密码
  • 应用账号不用 SUPER/FILE/PROCESS
  • local_infile=0
  • 定期审计 mysql.user
  • 敏感列加密 / 脱敏(应用层或 TDE 企业版)
  • 3306 仅内网、安全组白名单

5. SQL 基础与数据类型

5.1 DDL(库表管理)

sql 复制代码
-- 建库
CREATE DATABASE biz_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 建表(InnoDB + 主键 + 注释)
CREATE TABLE orders (
  id          BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
  order_no    VARCHAR(32)     NOT NULL COMMENT '订单号',
  user_id     BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
  amount      DECIMAL(12,2)   NOT NULL DEFAULT 0.00 COMMENT '金额',
  status      TINYINT         NOT NULL DEFAULT 0 COMMENT '0待付 1已付 2关闭',
  created_at  DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at  DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  UNIQUE KEY uk_order_no (order_no),
  KEY idx_user_status (user_id, status),
  KEY idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

-- 改表
ALTER TABLE orders ADD COLUMN remark VARCHAR(255) DEFAULT NULL AFTER status;
ALTER TABLE orders MODIFY amount DECIMAL(14,2) NOT NULL;
-- 在线 DDL(5.7,大表谨慎)
ALTER TABLE orders ALGORITHM=INPLACE, LOCK=NONE, ADD INDEX idx_remark (remark(64));

-- 删表
DROP TABLE IF EXISTS orders_bak;

5.2 DML

sql 复制代码
INSERT INTO orders (order_no, user_id, amount, status)
VALUES ('O20250624001', 1001, 99.90, 0);

INSERT INTO orders (order_no, user_id, amount, status) VALUES
('O20250624002', 1002, 199.00, 0),
('O20250624003', 1003, 49.90, 1);

UPDATE orders SET status = 1, updated_at = NOW() WHERE order_no = 'O20250624001' AND status = 0;

DELETE FROM orders WHERE status = 2 AND created_at < DATE_SUB(NOW(), INTERVAL 90 DAY) LIMIT 1000;

5.3 DQL 基础

sql 复制代码
SELECT id, order_no, amount FROM orders WHERE user_id = 1001 AND status = 1;
SELECT * FROM orders ORDER BY created_at DESC LIMIT 20 OFFSET 0;
SELECT status, COUNT(*) AS cnt, SUM(amount) AS total FROM orders GROUP BY status;
SELECT COUNT(DISTINCT user_id) FROM orders WHERE created_at >= '2025-06-01';

5.4 常用数据类型选型

类型 适用 注意
BIGINT UNSIGNED 主键、ID 不用 INT 做主键防耗尽
DECIMAL(M,D) 金额 不用 FLOAT/DOUBLE
VARCHAR(N) 变长字符串 N 按实际;索引过长用前缀
DATETIME 时间 不用字符串存时间
TINYINT 状态枚举 配合注释或字典表
JSON 半结构化(5.7+) 大字段慎索引
TEXT/BLOB 长文本 独立拆表或对象存储

5.5 事务控制

sql 复制代码
START TRANSACTION;   -- 或 BEGIN
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1001 AND balance >= 100;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 1002;
COMMIT;              -- 或 ROLLBACK;

-- 查看隔离级别
SELECT @@transaction_isolation;   -- 5.7.20+ 或 @@tx_isolation
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

6. SQL 组合查询与实战

6.1 多表 JOIN

sql 复制代码
-- INNER JOIN:两表匹配行
SELECT o.order_no, o.amount, u.username, u.mobile
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE o.status = 1 AND o.created_at >= '2025-06-01';

-- LEFT JOIN:保留左表全部
SELECT u.id, u.username, COUNT(o.id) AS order_cnt
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.status = 1
GROUP BY u.id, u.username;

-- 多表关联
SELECT o.order_no, oi.sku_name, oi.qty, oi.price
FROM orders o
INNER JOIN order_items oi ON o.id = oi.order_id
INNER JOIN users u ON o.user_id = u.id
WHERE o.created_at BETWEEN '2025-06-01' AND '2025-06-30';

运维注意 :JOIN 字段需同类型、有索引;避免大表无条件下笛卡尔积。

6.2 子查询

sql 复制代码
-- WHERE IN
SELECT * FROM orders
WHERE user_id IN (SELECT id FROM users WHERE level = 'VIP');

-- EXISTS(常比 IN 高效)
SELECT * FROM users u
WHERE EXISTS (
  SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = 1
);

-- 标量子查询
SELECT order_no, amount,
  (SELECT username FROM users u WHERE u.id = o.user_id) AS username
FROM orders o
WHERE o.status = 1;

-- FROM 子查询(派生表,5.7 无 CTE,用派生表代替)
SELECT t.status, t.cnt FROM (
  SELECT status, COUNT(*) AS cnt FROM orders GROUP BY status
) t WHERE t.cnt > 100;

6.3 UNION / UNION ALL

sql 复制代码
-- UNION 去重;UNION ALL 不去重(更快)
SELECT order_no, amount, created_at FROM orders_202506
UNION ALL
SELECT order_no, amount, created_at FROM orders_202505
ORDER BY created_at DESC
LIMIT 100;

6.4 GROUP BY 与 HAVING

sql 复制代码
-- 按用户统计订单
SELECT user_id,
       COUNT(*) AS order_cnt,
       SUM(amount) AS total_amount,
       MAX(created_at) AS last_order_time
FROM orders
WHERE created_at >= '2025-06-01'
GROUP BY user_id
HAVING order_cnt >= 5 AND total_amount > 1000
ORDER BY total_amount DESC
LIMIT 50;

6.5 常用聚合组合

sql 复制代码
-- 按日统计
SELECT DATE(created_at) AS dt,
       COUNT(*) AS orders,
       SUM(amount) AS gmv
FROM orders
WHERE created_at >= '2025-06-01'
GROUP BY DATE(created_at)
ORDER BY dt;

-- CASE 分段统计
SELECT
  SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS pending,
  SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS paid,
  SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS closed
FROM orders
WHERE created_at >= CURDATE();

6.6 运维实用 SQL 组合

sql 复制代码
-- 查表大小 Top 10
SELECT table_schema, table_name,
       ROUND(data_length/1024/1024, 2) AS data_mb,
       ROUND(index_length/1024/1024, 2) AS index_mb,
       table_rows
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
ORDER BY data_length + index_length DESC
LIMIT 10;

-- 查重复数据
SELECT order_no, COUNT(*) AS c FROM orders GROUP BY order_no HAVING c > 1;

-- 查无主键表
SELECT t.table_schema, t.table_name
FROM information_schema.tables t
LEFT JOIN information_schema.statistics s
  ON t.table_schema = s.table_schema AND t.table_name = s.table_name AND s.index_name = 'PRIMARY'
WHERE t.table_schema = 'biz_db' AND t.table_type = 'BASE TABLE' AND s.index_name IS NULL;

-- 查未使用索引(需开启记录)
SELECT * FROM sys.schema_unused_indexes WHERE object_schema = 'biz_db';

6.7 分页优化

sql 复制代码
-- 低效:深分页 OFFSET 大时全表扫描
SELECT * FROM orders ORDER BY id LIMIT 1000000, 20;

-- 推荐:延迟关联 / 游标
SELECT o.* FROM orders o
INNER JOIN (
  SELECT id FROM orders ORDER BY id LIMIT 1000000, 20
) t ON o.id = t.id;

-- 或记住上次最大 id
SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 20;

7. 索引与执行计划

7.1 索引类型

类型 说明
主键索引 聚簇索引,叶子存整行
唯一索引 列值唯一
普通索引 加速查询
联合索引 最左前缀原则

7.2 最左前缀

联合索引 (user_id, status, created_at) 可命中:

  • WHERE user_id = ?
  • WHERE user_id = ? AND status = ?
  • WHERE user_id = ? AND status = ? AND created_at > ?

不可单独命中 statuscreated_at(无 user_id 时)。

7.3 EXPLAIN 解读

sql 复制代码
EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND status = 1\G
关注点
type 性能:system > const > eq_ref > ref > range > index > ALL(全表扫描差)
key 实际使用索引
rows 预估扫描行数,越小越好
Extra Using filesort/Using temporary 需优化
filtered 5.7 过滤百分比
sql 复制代码
-- 查看索引使用情况
SHOW INDEX FROM orders;
ANALYZE TABLE orders;
OPTIMIZE TABLE orders;   -- 碎片整理,低峰执行

8. 事务、锁与死锁

8.1 锁类型

说明
共享锁 S SELECT ... LOCK IN SHARE MODE
排他锁 X UPDATE/DELETE/INSERTSELECT ... FOR UPDATE
意向锁 表级,与行锁协调
间隙锁 RR 下防幻读
临键锁 记录锁 + 间隙锁

8.2 死锁与锁阻塞排查

sql 复制代码
-- 查看最近一次死锁
SHOW ENGINE INNODB STATUS\G
-- 关注 LATEST DETECTED DEADLOCK 段

-- 当前锁等待(5.7)
SELECT * FROM information_schema.innodb_locks;
SELECT * FROM information_schema.innodb_lock_waits;
SELECT * FROM sys.innodb_lock_waits;

-- 进行中的事务
SELECT * FROM information_schema.innodb_trx ORDER BY trx_started DESC;
-- Kill 事务:KILL <trx_mysql_thread_id>

查看阻塞者并生成 KILL 语句(生产常用)

sql 复制代码
SELECT CURRENT_TIMESTAMP,
   pw.user AS pw_user, pw.db AS pw_db,
   SUBSTRING_INDEX(pw.host,':',1) AS pw_host,
   pw.COMMAND AS pw_command, pw.state AS pw_state,
   pw.INFO AS pw_sqltext, pw.id AS pw_processid, pw.TIME AS pw_time,
   r.trx_wait_started AS waiting_started,
   TIMEDIFF(NOW(), r.trx_wait_started) AS waiting_age,
   rl.lock_table AS waiting_locked_table,
   r.trx_mysql_thread_id AS waiting_pid,
   r.trx_query AS waiting_query,
   b.trx_mysql_thread_id AS blocking_pid,
   b.trx_query AS blocking_query,
   CONCAT('KILL ', b.trx_mysql_thread_id, ';') AS kill_sql,
   pb.user AS pb_user, pb.INFO AS pb_sqltext
FROM information_schema.innodb_lock_waits w
JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
JOIN information_schema.innodb_locks bl ON bl.lock_id = w.blocking_lock_id
JOIN information_schema.innodb_locks rl ON rl.lock_id = w.requested_lock_id
JOIN information_schema.processlist pw ON pw.id = r.trx_mysql_thread_id
JOIN information_schema.processlist pb ON pb.id = b.trx_mysql_thread_id
ORDER BY r.trx_id;
sql 复制代码
-- 长事务
SELECT trx_id, trx_started, trx_mysql_thread_id, trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;

-- 活跃非 Sleep 会话(排除复制)
SELECT CONCAT('KILL ', id, ';') AS kill_sql, id, user, host, db, state, command, time, LEFT(info, 50)
FROM information_schema.processlist
WHERE command <> 'Sleep' AND command <> 'Binlog Dump GTID'
ORDER BY time DESC;

8.3 死锁处理原则

  1. InnoDB 自动回滚代价小的事务,应用需有重试
  2. 固定顺序访问多表,减少交叉锁
  3. 缩短事务、避免大事务中交互等待
  4. 高并发热点行:拆分、队列、乐观锁

9. 备份与恢复

9.1 备份策略

类型 工具 场景
逻辑备份 mysqldump 小库、跨版本、结构导出
物理热备 xtrabackup 大库、生产不停机
binlog 连续归档 点对点恢复
快照 LVM/云盘 配合冷备/从库

3-2-1 原则:3 份副本、2 种介质、1 份异地。

9.2 mysqldump

bash 复制代码
# 全库(InnoDB 一致性,--single-transaction)
mysqldump -uroot -p --single-transaction --master-data=2 \
  --routines --triggers --events \
  --all-databases | gzip > /data/mysql/backup/all_$(date +%F).sql.gz

# 单库
mysqldump -uroot -p --single-transaction biz_db | gzip > biz_db_$(date +%F).sql.gz

# 仅结构
mysqldump -uroot -p -d biz_db > biz_db_schema.sql

生产环境单库备份(含 GTID 集群)

bash 复制代码
port=3306
dbname=visualdata
sock=/export/servers/data/my${port}/run/mysqld.sock
mysqldump=/export/servers/app/mysql-5.7.22/bin/mysqldump
ts=$(date +%Y%m%d_%H%M%S)

${mysqldump} -uroot -S ${sock} -p \
  --default-character-set=utf8 \
  --opt --hex-blob --skip-tz-utc \
  --add-drop-database=FALSE --add-drop-table=FALSE \
  --single-transaction \
  --set-gtid-purged=OFF \
  --log-error=${dbname}.full.sql.${ts}.err \
  ${dbname} > ${dbname}.full.sql.${ts} 2>${dbname}.full.sql.${ts}.log

单表备份

bash 复制代码
dbname=smartops
tablename=your_table
${mysqldump} -uroot -S ${sock} -p \
  --default-character-set=utf8 --opt --hex-blob --skip-tz-utc \
  --add-drop-database=FALSE --add-drop-table=FALSE \
  --single-transaction --set-gtid-purged=OFF \
  ${dbname} --tables ${tablename} > ${dbname}.${tablename}.sql.${ts}
参数 说明
--default-character-set=utf8 备份字符集
--opt 常用优化组合(quick、extended-insert 等)
--hex-blob BLOB 十六进制导出,防损坏
--skip-tz-utc 不写 SET TIME_ZONE='+00:00'
--add-drop-database/table=FALSE 不生成 DROP 语句
--single-transaction InnoDB 一致性快照
--set-gtid-purged=OFF GTID 环境避免污染目标
-R 备份存储过程/函数(需 SUPER 权限)

9.3 xtrabackup 热备

MySQL 5.7 使用 Percona XtraBackup 2.4.x(与 8.0 的 8.x 工具链不通用)。

bash 复制代码
# 全量(innobackupex 2.4 语法)
innobackupex --defaults-file=/export/servers/data/my3306/my.cnf \
  --user=dbbackup --password='xxx' \
  --backup --lock-ddl-per-table --slave-info \
  --parallel=6 \
  --socket=/export/servers/data/my3306/run/mysqld.sock \
  /export/backup

# 或使用 xtrabackup 命令
xtrabackup --defaults-file=/export/servers/data/my3306/my.cnf \
  --user=dbbackup --password='xxx' \
  --backup --lock-ddl-per-table --slave-info \
  --socket=/export/servers/data/my3306/run/mysqld.sock \
  --target-dir=/export/backupmysql/backup_3306/data/$(date +%y%m%d_%H_%M)

# 流式打包备份(适合大库传输)
innobackupex --defaults-file=/export/servers/data/my3306/my.cnf \
  --user=dbbackup --password='xxx' --slave-info \
  /tmp --stream=tar | gzip > /export/backup/full_$(date +%Y%m%d).tar.gz

# 生产定时脚本常用写法
innobackupex --defaults-file=${mycnfdir} --user=$username --password=$passwd \
  --lock-ddl-per-table --slave-info ${backup_path} \
  --stream=tar | gzip > ${backup_path}/full_$(date +%Y%m%d)bak.tar.gz
参数 说明
--lock-ddl-per-table 备份期间对单表 DDL 加锁,保证结构一致
--slave-info 生成主从位点/GTID 信息(xtrabackup_slave_info
--parallel=N 并行拷贝数据文件,大库加速
--slave-info + GTID xtrabackup_info 读取 gtid_purged

备份成功标志 :日志末尾出现 completed OK!,并生成:

文件 含义
xtrabackup_info 备份元信息、binlog 位点、GTID 范围
xtrabackup_binlog_info binlog 文件名与 position
xtrabackup_checkpoints LSN checkpoint
backup-my.cnf 备份时配置快照
bash 复制代码
# 增量基于 LSN
innobackupex --user=backup --password='xxx' --incremental /backup/inc \
  --incremental-basedir=/backup/full

# 准备(apply log)
innobackupex --apply-log /export/backup/2022-01-05_15-01-34/

9.4 恢复

bash 复制代码
# 逻辑恢复
gunzip < all_2025-06-24.sql.gz | mysql -uroot -p

# 单库
mysql -uroot -p biz_db < biz_db_2025-06-24.sql

# 基于 binlog 点对点(误删后)
mysqlbinlog --start-datetime='2025-06-24 10:00:00' \
  --stop-datetime='2025-06-24 10:05:00' \
  /data/mysql/logs/mysql-bin.000123 | mysql -uroot -p

9.5 备份巡检

bash 复制代码
# 验证备份可恢复(定期演练)
# 检查备份文件大小、时间
ls -lh /data/mysql/backup/
# binlog 是否堆积
SHOW BINARY LOGS;

10. 主从复制与高可用

10.1 复制原理

Slave SQL relay log Slave IO binlog Master Slave SQL relay log Slave IO binlog Master #mermaid-svg-y3TDOpYNsxzuScps{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-y3TDOpYNsxzuScps .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-y3TDOpYNsxzuScps .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-y3TDOpYNsxzuScps .error-icon{fill:#552222;}#mermaid-svg-y3TDOpYNsxzuScps .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-y3TDOpYNsxzuScps .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-y3TDOpYNsxzuScps .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-y3TDOpYNsxzuScps .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-y3TDOpYNsxzuScps .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-y3TDOpYNsxzuScps .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-y3TDOpYNsxzuScps .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-y3TDOpYNsxzuScps .marker{fill:#333333;stroke:#333333;}#mermaid-svg-y3TDOpYNsxzuScps .marker.cross{stroke:#333333;}#mermaid-svg-y3TDOpYNsxzuScps svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-y3TDOpYNsxzuScps p{margin:0;}#mermaid-svg-y3TDOpYNsxzuScps .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-y3TDOpYNsxzuScps text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-y3TDOpYNsxzuScps .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-y3TDOpYNsxzuScps .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-y3TDOpYNsxzuScps .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-y3TDOpYNsxzuScps .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-y3TDOpYNsxzuScps #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-y3TDOpYNsxzuScps .sequenceNumber{fill:white;}#mermaid-svg-y3TDOpYNsxzuScps #sequencenumber{fill:#333;}#mermaid-svg-y3TDOpYNsxzuScps #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-y3TDOpYNsxzuScps .messageText{fill:#333;stroke:none;}#mermaid-svg-y3TDOpYNsxzuScps .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-y3TDOpYNsxzuScps .labelText,#mermaid-svg-y3TDOpYNsxzuScps .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-y3TDOpYNsxzuScps .loopText,#mermaid-svg-y3TDOpYNsxzuScps .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-y3TDOpYNsxzuScps .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-y3TDOpYNsxzuScps .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-y3TDOpYNsxzuScps .noteText,#mermaid-svg-y3TDOpYNsxzuScps .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-y3TDOpYNsxzuScps .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-y3TDOpYNsxzuScps .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-y3TDOpYNsxzuScps .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-y3TDOpYNsxzuScps .actorPopupMenu{position:absolute;}#mermaid-svg-y3TDOpYNsxzuScps .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-y3TDOpYNsxzuScps .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-y3TDOpYNsxzuScps .actor-man circle,#mermaid-svg-y3TDOpYNsxzuScps line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-y3TDOpYNsxzuScps :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 事务提交写 binlog IO 线程拉取 binlog 写入 relay log SQL 线程重放 应用变更

10.2 主库配置

ini 复制代码
server-id = 1
log_bin = mysql-bin
binlog_format = ROW
gtid_mode = ON
enforce_gtid_consistency = ON
sql 复制代码
CREATE USER 'repl'@'10.%.%.%' IDENTIFIED BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.%.%.%';

10.3 从库配置

ini 复制代码
server-id = 2
relay_log = relay-bin
read_only = 1
super_read_only = 1
gtid_mode = ON
enforce_gtid_consistency = ON
sql 复制代码
CHANGE MASTER TO
  MASTER_HOST='10.0.0.1',
  MASTER_USER='repl',
  MASTER_PASSWORD='repl_password',
  MASTER_AUTO_POSITION=1;   -- GTID
START SLAVE;
SHOW SLAVE STATUS\G

关键字段

字段 正常值
Slave_IO_Running Yes
Slave_SQL_Running Yes
Seconds_Behind_Master 0 或很小
Last_IO_Error / Last_SQL_Error

10.4 主从故障切换(手工)

sql 复制代码
-- 1. 确认从库追上
SHOW SLAVE STATUS\G

-- 2. 停应用写主库

-- 3. 从库停复制并提升
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only = 0;

-- 4. 应用改连新主库
-- 5. 旧主修复后作为从库挂回

10.5 读写分离注意

  • 从库有延迟:Seconds_Behind_Master > 0 时读可能落后
  • 写后读一致:同连接读主库,或等待 GTID、缓存版本号
  • 中间件:MyCAT、ProxySQL、ShardingSphere

10.6 通过 xtrabackup 备份恢复搭建主从(生产实战)

来源:MySQL通过备份恢复的方式搭建主从.pdf。适用于新建从库主从不同步需重建 场景,比 mysqldump 更快,适合大库。

流程总览

#mermaid-svg-DjrDsKstgo115zOR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DjrDsKstgo115zOR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DjrDsKstgo115zOR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DjrDsKstgo115zOR .error-icon{fill:#552222;}#mermaid-svg-DjrDsKstgo115zOR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DjrDsKstgo115zOR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DjrDsKstgo115zOR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DjrDsKstgo115zOR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DjrDsKstgo115zOR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DjrDsKstgo115zOR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DjrDsKstgo115zOR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DjrDsKstgo115zOR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DjrDsKstgo115zOR .marker.cross{stroke:#333333;}#mermaid-svg-DjrDsKstgo115zOR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DjrDsKstgo115zOR p{margin:0;}#mermaid-svg-DjrDsKstgo115zOR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DjrDsKstgo115zOR .cluster-label text{fill:#333;}#mermaid-svg-DjrDsKstgo115zOR .cluster-label span{color:#333;}#mermaid-svg-DjrDsKstgo115zOR .cluster-label span p{background-color:transparent;}#mermaid-svg-DjrDsKstgo115zOR .label text,#mermaid-svg-DjrDsKstgo115zOR span{fill:#333;color:#333;}#mermaid-svg-DjrDsKstgo115zOR .node rect,#mermaid-svg-DjrDsKstgo115zOR .node circle,#mermaid-svg-DjrDsKstgo115zOR .node ellipse,#mermaid-svg-DjrDsKstgo115zOR .node polygon,#mermaid-svg-DjrDsKstgo115zOR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DjrDsKstgo115zOR .rough-node .label text,#mermaid-svg-DjrDsKstgo115zOR .node .label text,#mermaid-svg-DjrDsKstgo115zOR .image-shape .label,#mermaid-svg-DjrDsKstgo115zOR .icon-shape .label{text-anchor:middle;}#mermaid-svg-DjrDsKstgo115zOR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DjrDsKstgo115zOR .rough-node .label,#mermaid-svg-DjrDsKstgo115zOR .node .label,#mermaid-svg-DjrDsKstgo115zOR .image-shape .label,#mermaid-svg-DjrDsKstgo115zOR .icon-shape .label{text-align:center;}#mermaid-svg-DjrDsKstgo115zOR .node.clickable{cursor:pointer;}#mermaid-svg-DjrDsKstgo115zOR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DjrDsKstgo115zOR .arrowheadPath{fill:#333333;}#mermaid-svg-DjrDsKstgo115zOR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DjrDsKstgo115zOR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DjrDsKstgo115zOR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DjrDsKstgo115zOR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DjrDsKstgo115zOR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DjrDsKstgo115zOR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DjrDsKstgo115zOR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DjrDsKstgo115zOR .cluster text{fill:#333;}#mermaid-svg-DjrDsKstgo115zOR .cluster span{color:#333;}#mermaid-svg-DjrDsKstgo115zOR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DjrDsKstgo115zOR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DjrDsKstgo115zOR rect.text{fill:none;stroke-width:0;}#mermaid-svg-DjrDsKstgo115zOR .icon-shape,#mermaid-svg-DjrDsKstgo115zOR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DjrDsKstgo115zOR .icon-shape p,#mermaid-svg-DjrDsKstgo115zOR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DjrDsKstgo115zOR .icon-shape .label rect,#mermaid-svg-DjrDsKstgo115zOR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DjrDsKstgo115zOR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DjrDsKstgo115zOR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DjrDsKstgo115zOR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 主库 innobackupex 备份
传输到从库
从库清空数据目录
apply-log
copy-back
启动从库
SET gtid_purged + CHANGE MASTER
START SLAVE 验证

第一步:主库获取备份
bash 复制代码
mkdir -p /export/backup

innobackupex --defaults-file=/export/servers/data/my3306/my.cnf \
  --user=dbbackup --password='xxx' \
  --backup --lock-ddl-per-table --parallel=6 \
  --socket=/export/servers/data/my3306/run/mysqld.sock \
  --slave-info \
  /export/backup
# 成功标志:completed OK!

备份目录示例:/export/backup/2022-01-05_15-01-34/,内含业务库目录、ibdata1xtrabackup_info 等。

记录 binlog/GTID 信息(备份结束时日志会打印,也可事后查看):

bash 复制代码
cat /export/backup/2022-01-05_15-01-34/xtrabackup_info
# binlog_pos = filename 'mysql-bin.000027', position '9080176',
# GTID of the last change '6d22d516-baf5-11eb-91ad-00155d4b3c01:1-26214'
第二步:传输至从库
bash 复制代码
# 大文件可先打包
tar czf backup.tar.gz -C /export/backup 2022-01-05_15-01-34
scp backup.tar.gz slave-host:/export/backup/
第三步:从库恢复准备
  1. 从库安装同版本 MySQL + XtraBackup 2.4
  2. 新实例 :用 init_mysql.sh 初始化空实例(如 3307 端口),修改 server-id 与主库不同
  3. 重建从库:若实例已存在仅复制不同步,跳过初始化,直接停库清数据
bash 复制代码
/etc/init.d/mysql3307.server stop

cd /export/servers/data/my3307
rm -rf ./binlog/* ./data/* ./ibdata/* ./iblog/*

# 新目录结构(若新建)
mkdir -p my3307/{binlog,data,ibdata,iblog,log,run,tmp} -pv
# 拷贝主库 my.cnf 到 my3307,修改 server-id
touch /export/servers/data/my3307/log/mysqld-err.log
第四步:apply-log(应用 redo)
bash 复制代码
cd /export/backup/2022-01-05_15-01-34
innobackupex --apply-log ./
# 成功标志:completed OK!
第五步:copy-back(还原到数据目录)
bash 复制代码
# 方式一:拷贝(保留备份目录)
innobackupex --defaults-file=/export/servers/data/my3307/my.cnf \
  --copy-back /export/backup/2022-01-05_15-01-34

# 方式二:移动(节省磁盘)
xtrabackup --defaults-file=/export/servers/data/my3307/my.cnf \
  --move-back --target-dir=/export/backup/2022-01-05_15-01-34
bash 复制代码
chown -R mysql:myinstall /export/servers/data/my3307
/etc/init.d/mysql3307.server start
第六步:搭建 GTID 主从
bash 复制代码
mysql -uroot -p -S /export/servers/data/my3307/run/mysqld.sock
sql 复制代码
-- 1. 从 xtrabackup_info 获取 GTID 范围
-- cat /export/servers/data/my3307/data/xtrabackup_info

RESET MASTER;
SET GLOBAL gtid_purged='6d22d516-baf5-11eb-91ad-00155d4b3c01:1-26214';

CHANGE MASTER TO
  MASTER_HOST='172.18.80.107',
  MASTER_PORT=3306,
  MASTER_USER='repl',
  MASTER_PASSWORD='repl',
  MASTER_AUTO_POSITION=1;

START SLAVE;
SHOW SLAVE STATUS\G

验证通过标准

字段 期望值
Slave_IO_Running Yes
Slave_SQL_Running Yes
Seconds_Behind_Master 0
Auto_Position 1
Last_IO_Error / Last_SQL_Error
注意事项
  • gtid_purged 必须与 xtrabackup_info完全一致
  • 从库 server-id 必须唯一;read_only=1super_read_only=1
  • apply-log 提示 already prepared,说明已执行过,可直接 copy-back
  • 主库备份期间尽量避开大 DDL;已用 --lock-ddl-per-table 降低风险

10.7 MHA 高可用启停

来源:数据库日常维护操作手册.docx。适用于 MHA + VIP 架构。

环境示例
角色 IP 说明
主库 10.7.87.136 server-id=223306
从库 10.7.87.137
MHA Manager 10.7.87.34
VIP 10.7.87.138 应用连接地址
网关 10.7.87.254 arping 用
关闭顺序
复制代码
关闭 MHA → 主库摘 VIP → 停主库 → 停从库
bash 复制代码
# 1. MHA 节点:停高可用
cd /service
systemctl stop daemontools.service
# 仅停单个 MHA 实例:
# svc -d /service/masterha_chengxu/

# 2. 主节点:摘 VIP + 停 MySQL
ifconfig bond0:0 down
/etc/init.d/mysql3306 stop
ps -ef | grep mysqld    # 确认已关闭

# 3. 从节点:停 MySQL
/etc/init.d/mysql3306 stop
ps -ef | grep mysqld
启动顺序
复制代码
启主库(改读写)→ 启从库(START SLAVE)→ 挂 VIP → 启 MHA
bash 复制代码
# 1. 主节点
/etc/init.d/mysql3306 start
mysql -uroot -p -S /export/servers/data/my3306/run/mysqld.sock

mysql> SHOW SLAVE STATUS\G
-- 主库应 Empty set(无复制配置)

mysql> SHOW VARIABLES LIKE '%read_only%';
-- 若 read_only=ON,改为可写:
SET GLOBAL read_only=OFF;
SET GLOBAL super_read_only=OFF;

# 2. 从节点
/etc/init.d/mysql3306 start
mysql -uroot -p -S /export/servers/data/my3306/run/mysqld.sock

mysql> SHOW SLAVE STATUS\G
-- 若 IO/SQL 为 No:
mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G
-- 确认 Slave_IO_Running=Yes, Slave_SQL_Running=Yes

# 3. 主节点挂 VIP
/sbin/ifconfig bond0:0 10.7.87.138 netmask 255.255.255.0
/sbin/arping -c 3 -s 10.7.87.138 -I bond0 10.7.87.254

# 4. 启动 MHA
systemctl start daemontools.service

11. 性能监控与慢查询

11.1 关键状态指标

sql 复制代码
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_running';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Created_tmp%';
SHOW GLOBAL STATUS LIKE 'Select_scan';
SHOW GLOBAL STATUS LIKE 'Aborted_connects';

-- 缓存命中率(参考)
-- (1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) * 100%

11.2 慢查询

ini 复制代码
slow_query_log = 1
slow_query_log_file = /data/mysql/logs/slow.log
long_query_time = 1
log_slow_admin_statements = 1
bash 复制代码
# pt-query-digest 分析
pt-query-digest /data/mysql/logs/slow.log > slow_report.txt

11.3 Performance Schema / sys

sql 复制代码
-- 当前最耗时的 SQL(需开启 performance_schema)
SELECT * FROM sys.statement_analysis LIMIT 10;

-- 全表扫描最多的表
SELECT * FROM sys.schema_tables_with_full_table_scans LIMIT 10;

-- 等待事件
SELECT * FROM sys.waits_global_by_latency LIMIT 10;

11.4 告警建议

指标 阈值(参考)
Threads_running 持续 > CPU 核数 × 2
连接数 > max_connections × 80%
复制延迟 > 60s
磁盘使用率 > 85%
慢查询增长率 突增
死锁 频繁出现

12. 性能调优

12.1 连接层

  • 应用使用连接池,避免频繁建连
  • max_connections 不是越大越好
  • Aborted_connectsThreads_cached

12.2 InnoDB

sql 复制代码
-- Buffer Pool 命中率
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';

-- 脏页比例
SHOW STATUS LIKE 'Innodb_buffer_pool_pages%';
  • 大表分区/归档,控制单表体量
  • 合理索引,定期 ANALYZE TABLE
  • 避免 SELECT *、大事务、热点行竞争

12.3 硬件与 OS

建议
磁盘 SSD/NVMe;数据与 binlog 分盘更佳
文件系统 XFS/ext4;noatime
内存 给 Buffer Pool;避免 swap(swappiness=1
网络 主从同机房低延迟

12.4 参数调优流程

复制代码
1. 定位瓶颈(CPU/IO/锁/慢 SQL)
2. 看监控 + EXPLAIN + SHOW PROFILE
3. 先 SQL/索引,后参数
4. 一次改一项,对比验证
5. 低峰变更,保留回滚

13. 日常运维命令

本节整合 数据库日常维护操作手册.docx 中 MySQL 生产操作指令。

13.1 服务与连接

bash 复制代码
# systemd 或自定义脚本
/etc/init.d/mysql3306 start|stop|status
systemctl start|stop mysqld

mysqladmin -uroot -p ping
mysqladmin -uroot -p status
mysqladmin -uroot -p processlist

# 登录(多实例用 socket)
/export/servers/app/mysql-5.7.22/bin/mysql -uroot -p \
  -S /export/servers/data/my3306/run/mysqld.sock
sql 复制代码
-- 连接数相关
SHOW VARIABLES LIKE '%conn%';
-- max_connections / max_user_connections / connect_timeout

-- 正在执行的 SQL
SELECT * FROM information_schema.processlist WHERE info IS NOT NULL;

13.2 库表维护

sql 复制代码
-- 查看库字符集后建库
SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME = 'bank_data';

CREATE DATABASE bank_data CHARACTER SET utf8 COLLATE utf8_general_ci;

-- 表结构与注释
SHOW CREATE TABLE orders\G;

-- 修改字段长度(保留原 NOT NULL / DEFAULT / COMMENT)
ALTER TABLE orders MODIFY COLUMN channel_name VARCHAR(500) NOT NULL DEFAULT '' COMMENT '通道名称';

-- 根据表名反查库名
SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_NAME = '已知表名';

13.3 容量与表空间

sql 复制代码
-- 库大小(GB)
SELECT SUM(data_length)/1024/1024/1024
FROM information_schema.tables
WHERE table_schema = UPPER('foreigntrade_db');

-- 单表大小(GB)
SELECT SUM(data_length)/1024/1024/1024
FROM information_schema.tables
WHERE table_schema = UPPER('foreigntrade_db') AND table_name = 'for_access_manifest';

-- 友好显示 MB
SELECT CONCAT(SUM(data_length)/1024/1024, ' MB') AS size
FROM information_schema.tables
WHERE table_schema = UPPER('foreigntrade_db') AND table_name = 'for_access_manifest';

-- 表行数估算
SELECT table_rows FROM information_schema.tables
WHERE table_schema = 'biz_db' AND table_name = 'orders';

-- 精确行数
SELECT COUNT(*) FROM orders;

13.4 进程、事务与会话

sql 复制代码
SHOW FULL PROCESSLIST;

KILL QUERY 12345;   -- 仅终止当前语句
KILL 12345;         -- 断开连接

-- 会话历史(Performance Schema)
SELECT b.processlist_id, c.db, c.user, a.sql_text, c.command, c.time, c.state
FROM performance_schema.events_statements_history a
JOIN performance_schema.threads b USING(thread_id)
JOIN information_schema.processlist c ON b.processlist_id = c.id
WHERE c.id = 50658
ORDER BY a.EVENT_ID;

-- 线程内存占用
SELECT mt.thread_id,
  SUM(mt.current_count_used) AS current_count_used,
  CAST(ROUND(SUM(mt.current_number_of_bytes_used)/1024/1024) AS SIGNED) AS current_allocated_mb,
  t.processlist_user, t.processlist_db, t.processlist_info, t.processlist_time
FROM performance_schema.memory_summary_by_thread_by_event_name mt
INNER JOIN performance_schema.threads t ON mt.thread_id = t.thread_id
WHERE t.processlist_db IS NOT NULL AND t.name = 'thread/sql/one_connection'
GROUP BY mt.thread_id
ORDER BY current_allocated_mb DESC;

13.5 binlog 管理

sql 复制代码
SHOW MASTER LOGS;
SHOW BINARY LOGS;

-- 按时间清理
PURGE BINARY LOGS BEFORE '2025-06-20 17:00:00';

-- 按文件清理(删除 mysql-bin.000006 之前)
PURGE BINARY LOGS TO 'mysql-bin.000006';
bash 复制代码
# 解析 binlog(ROW 模式建议 DECODE-ROWS)
mysqlbinlog --base64-output=DECODE-ROWS -vv mysql-bin.000008 > mysql-bin.000008.log

# 按时间范围导出用于恢复
mysqlbinlog --start-datetime='2025-06-24 10:00:00' \
  --stop-datetime='2025-06-24 10:05:00' mysql-bin.000200 > recover.sql

13.6 索引审计

sql 复制代码
-- 未使用的索引
SELECT * FROM sys.schema_unused_indexes
WHERE object_schema = 'cityos' AND object_name IN ('table1')
ORDER BY object_name;

-- 冗余索引
SELECT table_schema, table_name, redundant_index_name, redundant_index_columns,
       dominant_index_name, dominant_index_columns
FROM sys.schema_redundant_indexes
WHERE table_schema != 'performance_schema';

13.7 数据导出

sql 复制代码
-- 导出 CSV(目录需有写权限,常用 /tmp)
SELECT column1, column2 INTO OUTFILE '/tmp/export.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM your_table WHERE your_conditions;

13.8 日志查看

bash 复制代码
# 错误日志
tail -200 /export/servers/data/my3306/log/mysqld-err.log
# 或 more /export/server/data/my3306/log/mysqld-err.log

# 慢日志分析 Top SQL
pt-query-digest --type slowlog \
  --since "2025-06-24 17:01:00" --until "2025-06-24 17:05:00" \
  slow.log > slow_report.txt
sql 复制代码
-- general log(仅排障临时开启,生产慎开)
SHOW VARIABLES WHERE Variable_name IN ('general_log','general_log_file');
SET GLOBAL general_log = ON;
-- 排查完毕关闭
SET GLOBAL general_log = OFF;

13.9 主从状态

sql 复制代码
SHOW SLAVE STATUS\G
-- 关注 Slave_IO_Running / Slave_SQL_Running / Seconds_Behind_Master

13.10 GTID 跳过单事务(慎用)

仅当确认可跳过某条冲突 GTID 时使用,需 DBA 审批。

sql 复制代码
SET @@SESSION.GTID_NEXT = 'ece7b132-33c5-11e8-bfd6-e8611f23c126:256649553';
BEGIN; COMMIT;
SET @@SESSION.GTID_NEXT = 'AUTOMATIC';

13.11 空间清理

sql 复制代码
PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);
ALTER TABLE orders DROP PARTITION p202401;   -- 若已分区

13.12 版本与升级

sql 复制代码
SELECT VERSION();
SHOW VARIABLES LIKE 'version%';

5.7 升级路径:5.7 → 8.0 需 mysql_upgrade、检查兼容性;小版本低峰滚动重启从库再主库。


14. 故障排查手册

14.1 无法连接

现象 排查 处理
Can't connect 进程、端口、防火墙 systemctl start mysqld;开放 3306
Too many connections Threads_connected 杀空闲连接;调大 max_connections;修连接泄漏
Access denied 用户/host/密码 SHOW GRANTS;重置密码
Host is blocked max_connect_errors FLUSH HOSTS;修网络抖动
bash 复制代码
ss -lntp | grep 3306
tail -100 /data/mysql/logs/error.log

14.2 磁盘满

bash 复制代码
df -h
du -sh /data/mysql/*
sql 复制代码
-- 查大表
SELECT table_schema, table_name,
  ROUND((data_length+index_length)/1024/1024/1024,2) AS gb
FROM information_schema.tables
ORDER BY data_length+index_length DESC LIMIT 20;

-- 应急:清理 binlog、慢日志、临时表、归档历史数据
PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 1 DAY);

14.3 主从复制异常

sql 复制代码
SHOW SLAVE STATUS\G
错误 原因 处理
IO 线程 No 网络、账号、server-id Last_IO_ErrorCHANGE MASTER
SQL 线程 No 数据不一致、DDL 冲突 STOP SLAVE; SET GLOBAL sql_slave_skip_counter=1; START SLAVE;慎用
延迟大 从库性能、大事务、单线程回放 并行复制 slave_parallel_workers;优化慢 SQL
GTID 冲突 误操作双写 [GTID 跳过](#错误 原因 处理 IO 线程 No 网络、账号、server-id 查 Last_IO_Error;CHANGE MASTER SQL 线程 No 数据不一致、DDL 冲突 STOP SLAVE; SET GLOBAL sql_slave_skip_counter=1; START SLAVE;(慎用) 延迟大 从库性能、大事务、单线程回放 并行复制 slave_parallel_workers;优化慢 SQL GTID 冲突 误操作双写 GTID 跳过 或 rebuild 从库(见 10.6)) 或 rebuild 从库(见 [10.6](#错误 原因 处理 IO 线程 No 网络、账号、server-id 查 Last_IO_Error;CHANGE MASTER SQL 线程 No 数据不一致、DDL 冲突 STOP SLAVE; SET GLOBAL sql_slave_skip_counter=1; START SLAVE;(慎用) 延迟大 从库性能、大事务、单线程回放 并行复制 slave_parallel_workers;优化慢 SQL GTID 冲突 误操作双写 GTID 跳过 或 rebuild 从库(见 10.6)))

重建从库(常用) :见 [10.6 通过 xtrabackup 备份恢复搭建主从](#10.6 通过 xtrabackup 备份恢复搭建主从)。

14.4 锁等待 / 库卡死

sql 复制代码
-- 谁阻塞谁
SELECT w.requesting_trx_id, w.blocking_trx_id,
       pl1.info AS requesting_sql, pl2.info AS blocking_sql
FROM information_schema.innodb_lock_waits w
JOIN information_schema.innodb_trx t1 ON w.requesting_trx_id = t1.trx_id
JOIN information_schema.innodb_trx t2 ON w.blocking_trx_id = t2.trx_id
JOIN information_schema.processlist pl1 ON t1.trx_mysql_thread_id = pl1.id
JOIN information_schema.processlist pl2 ON t2.trx_mysql_thread_id = pl2.id;

-- 杀阻塞源
KILL <blocking_thread_id>;

14.5 慢查询突增

复制代码
1. pt-query-digest 看 Top SQL
2. EXPLAIN 是否走索引
3. 是否统计信息过期 → ANALYZE TABLE
4. 是否缓存失效 / 业务放量
5. 是否锁等待导致堆积

14.6 数据误删恢复

复制代码
1. 立即停止写入(只读、摘流量)
2. 确认误操作时间点
3. 全备 + binlog 恢复到新实例验证
4. 回灌或切换
bash 复制代码
mysqlbinlog --start-datetime='2025-06-24 14:00:00' \
  --stop-datetime='2025-06-24 14:10:00' \
  mysql-bin.000200 > recover.sql
# 手工编辑 recover.sql 去掉误操作语句后导入

14.7 表损坏

sql 复制代码
CHECK TABLE orders;
-- InnoDB 多数情况可恢复
-- 严重:xtrabackup 恢复或 innodb_force_recovery(最后手段,可能丢数据)
ini 复制代码
# my.cnf 应急(1→6 逐级尝试,仅恢复导出用)
innodb_force_recovery = 1

15. 故障处理 SOP

SOP-1:连接数打满

复制代码
1. mysqladmin processlist 看 Sleep 与 Running 比例
2. 应用是否连接泄漏(未 close)
3. 临时 KILL 长 Sleep(需审批)
4. 必要时调 max_connections(治标)
5. 复盘连接池配置

SOP-2:主从延迟过高

复制代码
1. SHOW SLAVE STATUS → Seconds_Behind_Master
2. 从库 SHOW PROCESSLIST 是否在跑大 SQL
3. 主库是否有大事务 / DDL
4. 开启 parallel workers;优化慢 SQL
5. 延迟持续 > 阈值 → 读流量切主或降级

SOP-3:死锁频发

复制代码
1. SHOW ENGINE INNODB STATUS 取死锁日志
2. 对齐应用 SQL 加锁顺序
3. 缩短事务、索引优化
4. 应用侧重试机制

SOP-4:数据库 CPU 100%

复制代码
1. SHOW PROCESSLIST 找耗时 SQL
2. EXPLAIN + 索引
3. 是否缓存击穿 / 全表扫描
4. 限流、读写分离

SOP-5:紧急只读(保护数据)

sql 复制代码
SET GLOBAL read_only = 1;
SET GLOBAL super_read_only = 1;   -- 5.7 super 权限也禁止写
-- 恢复
SET GLOBAL read_only = 0;
SET GLOBAL super_read_only = 0;

16. 日常巡检清单

每日

  • 实例存活:mysqladmin ping
  • 连接数 / Threads_running
  • 复制状态:Slave_IO/SQL_RunningSeconds_Behind_Master
  • 磁盘空间 < 80%
  • 错误日志无新 Fatal
  • 慢查询量无异常突增
  • 备份任务成功

每周

  • 大表增长趋势
  • binlog 占用与保留策略
  • 索引冗余 / 未使用索引
  • 长事务、死锁统计
  • 备份恢复演练(抽样)

每月

  • 账号权限审计
  • 参数回顾与容量规划
  • 小版本安全补丁评估
  • information_schema 碎片整理计划

17. 值班速查

告警 第一步 关键命令
连接失败 进程/端口/错误日志 systemctl status mysqldtail error.log
连接数高 processlist SHOW PROCESSLISTKILL
复制中断 slave status SHOW SLAVE STATUS\G
复制延迟 从库负载 Seconds_Behind_Master、慢 SQL
磁盘满 大表/binlog PURGE BINARY LOGS、归档
CPU 高 活跃 SQL PROCESSLISTEXPLAIN
死锁 innodb status SHOW ENGINE INNODB STATUS\G
数据误操作 停写 全备 + mysqlbinlog 恢复

禁止未经审批的操作

  • 生产 DROP DATABASE / TRUNCATE 大表
  • 随意 sql_slave_skip_counter
  • 随意调高 innodb_force_recovery
  • 无备份情况下执行不可逆 DDL

18. 在线 DDL 与 gh-ost

来源:数据库日常维护操作手册.docx。大表结构变更优先用 gh-ost ,避免原生 ALTER TABLE 长时间锁表。

18.1 原生在线 DDL(5.7)

sql 复制代码
ALTER TABLE orders ALGORITHM=INPLACE, LOCK=NONE, ADD INDEX idx_remark (remark(64));

仍可能因元数据锁、重建表等导致抖动,GB 级表建议 gh-ost

18.2 gh-ost 示例

bash 复制代码
gh-ost \
  --user="root" --password="******" \
  --host=10.241.241.224 --port=3306 \
  --database="order" --table="orderinfo" \
  --alter="ADD KEY ind_account (trans_account)" \
  --allow-on-master \
  --initially-drop-old-table \
  --initially-drop-ghost-table \
  --allow-nullable-unique-key \
  --max-load=Threads_connected=1500 \
  --critical-load=Threads_connected=4000 \
  --chunk-size=200000 \
  --max-lag-millis=1500 \
  --initially-drop-socket-file \
  --verbose \
  --execute
参数 说明
--allow-on-master 允许在主库执行(无独立从库时)
--max-load / --critical-load 负载过高时暂停迁移
--chunk-size 每批拷贝行数
--max-lag-millis 主从延迟超阈值则暂停
--execute 不加则仅 dry-run

18.3 变更前检查清单

  • 已在预发验证 DDL
  • 磁盘空间 ≥ 表大小 2 倍
  • 低峰窗口 + 回滚方案(gh-ost 可 panic 中断)
  • 主从延迟正常

附录:MySQL 5.7 与 8.0 差异速查

特性 5.7 8.0
窗口函数 不支持 支持
CTE(WITH) 不支持 支持
默认字符集 latin1(建议改 utf8mb4) utf8mb4
认证插件 mysql_native_password caching_sha2_password
查询缓存 有(8.0 移除)
不可见索引 不支持 支持
直方图 不支持 支持

附录:常用 information_schema 查询

sql 复制代码
-- 当前所有连接
SELECT id, user, host, db, command, time, state, LEFT(info,100) AS sql_text
FROM information_schema.processlist ORDER BY time DESC;

-- 表字段信息
SELECT column_name, column_type, is_nullable, column_key, column_comment
FROM information_schema.columns
WHERE table_schema = 'biz_db' AND table_name = 'orders';

-- 外键
SELECT * FROM information_schema.key_column_usage
WHERE table_schema = 'biz_db' AND referenced_table_name IS NOT NULL;