系统运维人员MySQL数据库完全掌握指南:从基础指令到生产实战
作为一名系统运维工程师,无论你负责的是Web应用、微服务架构还是大数据平台,MySQL数据库几乎是绕不开的核心组件。根据DB-Engines 2026年最新排名,MySQL依然稳居全球最受欢迎的开源数据库榜首,市场份额超过40%。在生产环境中,MySQL的稳定性、性能和安全性直接决定了整个业务系统的可用性。
很多运维人员对MySQL的认知停留在”会安装、会重启、会备份”的基础层面,但在实际生产环境中,你可能会遇到各种复杂问题:数据库突然变慢、主从同步中断、数据意外删除、连接数打满、死锁频发等等。这些问题如果处理不当,轻则导致业务响应缓慢,重则造成数据丢失和服务长时间中断。
本文将系统梳理系统运维人员必须掌握的MySQL核心能力体系,并详细讲解生产环境中最常用的MySQL指令及其应用场景,帮助你从”MySQL使用者”成长为”MySQL运维专家”。
本文适用对象
- 系统运维工程师(1-5年工作经验)
- 数据库管理员(DBA)
- DevOps工程师
- 后端开发人员(需要了解数据库运维)
一、运维人员MySQL核心能力体系
1.1 MySQL基础架构与原理
在深入学习指令之前,你必须先理解MySQL的基础架构,这是所有运维操作的理论基础。
MySQL采用客户端/服务器架构,主要由以下几个部分组成:
连接层(Connection Layer)
- 处理客户端连接请求
- 身份验证和权限校验
- 连接线程管理
- 连接池维护
服务层(Service Layer)
- 查询解析器(Parser):将SQL语句解析成语法树
- 查询优化器(Optimizer):选择最优的执行计划
- 查询缓存(Query Cache):缓存查询结果(MySQL 8.0已移除)
- 存储过程、触发器、视图等功能模块
存储引擎层(Storage Engine Layer)
- InnoDB:支持事务、外键、行级锁,默认引擎
- MyISAM:不支持事务,表级锁,读性能好
- Memory:数据存储在内存中,速度快但重启丢失
- Archive:高度压缩,适合历史归档数据
文件系统层(File System Layer)
- 数据文件(.ibd、.frm)
- 日志文件(redo log、undo log、binlog、error log、slow log)
- 配置文件(my.cnf/my.ini)
重点关注InnoDB对于运维人员来说,最重要的是理解InnoDB存储引擎的架构,因为它是MySQL 5.5及以上版本的默认引擎,也是生产环境中使用最广泛的引擎。
InnoDB核心架构详解
内存结构(In-Memory Structures)
-
Buffer Pool(缓冲池):最重要的内存区域,用于缓存表数据和索引数据
- 默认大小为128MB,生产环境建议设置为物理内存的50%-70%
- 采用LRU算法进行页面淘汰
- 包含数据页、索引页、undo页、插入缓冲、自适应哈希索引等
-
Change Buffer(写缓冲):缓存对非唯一二级索引的DML操作
- 减少随机I/O,提高写入性能
- 默认占用Buffer Pool的25%
-
Adaptive Hash Index(自适应哈希索引):InnoDB自动创建的内存哈希索引
- 监控索引访问模式,自动为热点数据建立哈希索引
- 可以通过
innodb_adaptive_hash_index参数控制
-
Log Buffer(日志缓冲区):存储即将写入redo log的数据
- 默认大小为16MB
- 通过
innodb_log_buffer_size参数配置
磁盘结构(On-Disk Structures)
-
System Tablespace(系统表空间):存储InnoDB数据字典、undo log、change buffer等
- 文件名为ibdata1、ibdata2等
- 可以通过
innodb_data_file_path配置
-
File-Per-Table Tablespaces(独立表空间):每个表一个.ibd文件
- 通过
innodb_file_per_table=ON启用(MySQL 5.6.6+默认开启) - 便于管理和空间回收
- 通过
-
Redo Log Files(重做日志):记录数据页的物理修改
- 用于崩溃恢复,保证数据持久性
- 默认有ib_logfile0和ib_logfile1两个文件
- 循环写入,通过
innodb_log_file_size和innodb_log_files_in_group配置
-
Undo Log Files(回滚日志):记录事务修改前的数据
- 用于事务回滚和MVCC
- 存储在系统表空间或独立的undo表空间中
InnoDB事务与锁机制
ACID特性实现
- 原子性(Atomicity):通过undo log实现
- 一致性(Consistency):通过数据库约束和应用层保证
- 隔离性(Isolation):通过MVCC和锁机制实现
- 持久性(Durability):通过redo log和doublewrite buffer实现
四种隔离级别
-- 查看当前隔离级别SELECT @@transaction_isolation;SELECT @@global.transaction_isolation;
-- 设置会话级别隔离级别SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置全局隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
|---|---|---|---|---|
| READ UNCOMMITTED | 是 | 是 | 是 | 最低级别,不推荐 |
| READ COMMITTED | 否 | 是 | 是 | Oracle默认级别 |
| REPEATABLE READ | 否 | 否 | 是(InnoDB通过间隙锁解决) | MySQL默认级别 |
| SERIALIZABLE | 否 | 否 | 否 | 最高级别,性能最差 |
生产环境隔离级别选择大多数生产环境使用MySQL默认的
REPEATABLE READ隔离级别。如果对读一致性要求不高,可以使用READ COMMITTED来获得更好的并发性能。
锁的类型与应用
-- 查看当前持有的锁SELECT * FROM performance_schema.data_locks\G
-- 查看锁等待情况SELECT * FROM performance_schema.data_lock_waits\G
-- 查看InnoDB锁状态(老版本)SHOW ENGINE INNODB STATUS\G1.2 安装部署与配置管理
这是运维人员最基础的技能,但也是最容易出错的环节。
多种安装方式对比
| 安装方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| YUM/APT包管理器 | 简单快速,自动解决依赖 | 版本可能较旧 | 快速测试环境 |
| RPM/DEB包 | 版本可控,便于管理 | 需手动解决依赖 | 标准化部署 |
| 二进制包 | 无需编译,开箱即用 | 体积较大 | 生产环境推荐 |
| 源码编译 | 可自定义配置,性能最优 | 编译耗时,复杂度高 | 特殊需求场景 |
| Docker容器 | 快速部署,环境隔离 | 持久化需注意 | 开发测试环境 |
YUM方式安装MySQL 8.0(CentOS/RHEL)
# 1. 下载MySQL官方YUM仓库wget https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm
# 2. 安装YUM仓库sudo rpm -Uvh mysql80-community-release-el7-7.noarch.rpm
# 3. 查看可用的MySQL版本yum repolist all | grep mysql
# 4. 安装MySQL服务器sudo yum install mysql-community-server -y
# 5. 启动MySQL服务sudo systemctl start mysqldsudo systemctl enable mysqld
# 6. 查看初始root密码(MySQL 8.0会生成临时密码)sudo grep 'temporary password' /var/log/mysqld.log
# 7. 使用临时密码登录并修改密码mysql -uroot -p# {8}
# 8. 修改root密码(需要满足密码强度要求)ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPassword123!';FLUSH PRIVILEGES;初始密码安全MySQL 8.0首次启动时会生成一个临时密码,必须立即修改。如果找不到临时密码,可以通过
--skip-grant-tables选项跳过权限表启动MySQL,然后重置密码。
二进制包安装MySQL(推荐生产环境)
# 1. 创建mysql用户和组groupadd mysqluseradd -r -g mysql -s /bin/false mysql
# 2. 下载并解压二进制包cd /usr/localwget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.35-linux-glibc2.28-x86_64.tar.xztar xvf mysql-8.0.35-linux-glibc2.28-x86_64.tar.xzln -s mysql-8.0.35-linux-glibc2.28-x86_64 mysql
# 3. 创建数据目录mkdir -p /data/mysql/{data,logs,tmp}chown -R mysql:mysql /data/mysql
# 4. 创建配置文件cat > /etc/my.cnf << 'EOF'[mysqld]# 基础配置user = mysqlport = 3306basedir = /usr/local/mysqldatadir = /data/mysql/datasocket = /tmp/mysql.sockpid-file = /data/mysql/mysql.pid
# 字符集配置character-set-server = utf8mb4collation-server = utf8mb4_unicode_ci
# InnoDB配置innodb_buffer_pool_size = 2Ginnodb_log_file_size = 512Minnodb_log_files_in_group = 2innodb_flush_log_at_trx_commit = 2innodb_file_per_table = ONinnodb_data_file_path = ibdata1:100M:autoextend
# 日志配置log_error = /data/mysql/logs/error.logslow_query_log = ONslow_query_log_file = /data/mysql/logs/slow.loglong_query_time = 2log_queries_not_using_indexes = ON
# 连接配置max_connections = 500max_connect_errors = 100wait_timeout = 300interactive_timeout = 300
# 其他优化skip_name_resolve = ONsql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTIONEOF
# 5. 初始化数据库cd /usr/local/mysqlbin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql/data
# 6. 查看初始密码grep 'temporary password' /data/mysql/logs/error.log
# 7. 配置systemd服务cat > /etc/systemd/system/mysqld.service << 'EOF'[Unit]Description=MySQL ServerAfter=network.target
[Service]Type=forkingUser=mysqlGroup=mysqlExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnfExecStop=/usr/local/mysql/bin/mysqladmin -uroot -p shutdownRestart=on-failureRestartSec=5
[Install]WantedBy=multi-user.targetEOF
# 8. 启动MySQL服务systemctl daemon-reloadsystemctl start mysqldsystemctl enable mysqld
# 9. 配置环境变量echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profilesource /etc/profilemy.cnf核心参数详解
[client]port = 3306socket = /tmp/mysql.sock
[mysqld]# ============ 基础配置 ============user = mysqlport = 3306basedir = /usr/local/mysqldatadir = /data/mysql/datasocket = /tmp/mysql.sockpid-file = /data/mysql/mysql.pidtmpdir = /data/mysql/tmp
# ============ 字符集配置 ============character-set-server = utf8mb4collation-server = utf8mb4_unicode_ciinit_connect = 'SET NAMES utf8mb4'
# ============ 连接配置 ============max_connections = 500 # 最大连接数max_connect_errors = 100 # 最大错误连接数max_allowed_packet = 64M # 最大数据包大小wait_timeout = 300 # 连接空闲超时时间(秒)interactive_timeout = 300 # 交互式连接超时时间(秒)connect_timeout = 10 # 连接超时时间(秒)
# ============ InnoDB核心配置 ============innodb_buffer_pool_size = 4G # 缓冲池大小,设置为物理内存的50%-70%innodb_buffer_pool_instances = 4 # 缓冲池实例数,建议1G配置1个实例innodb_log_file_size = 512M # 重做日志大小innodb_log_files_in_group = 2 # 重做日志文件数量innodb_log_buffer_size = 16M # 日志缓冲区大小innodb_flush_log_at_trx_commit = 2 # 日志刷盘策略(0最快但不安全,1最安全但最慢,2折中)innodb_flush_method = O_DIRECT # 文件刷盘方法innodb_file_per_table = ON # 每个表使用独立表空间innodb_data_file_path = ibdata1:100M:autoextend # 系统表空间配置innodb_autoextend_increment = 64 # 自动扩展增量(MB)innodb_open_files = 1000 # InnoDB最大打开文件数innodb_io_capacity = 2000 # 磁盘IO能力innodb_io_capacity_max = 4000 # 磁盘IO能力上限innodb_read_io_threads = 4 # 读IO线程数innodb_write_io_threads = 4 # 写IO线程数
# ============ 日志配置 ============log_error = /data/mysql/logs/error.loglog_error_verbosity = 2 # 错误日志详细程度(1-3)
# 慢查询日志slow_query_log = ONslow_query_log_file = /data/mysql/logs/slow.loglong_query_time = 2 # 慢查询阈值(秒)log_queries_not_using_indexes = ON # 记录未使用索引的查询log_throttle_queries_not_using_indexes = 10 # 限制未使用索引日志的记录频率
# 二进制日志(用于主从复制和时间点恢复)log_bin = /data/mysql/logs/mysql-binbinlog_format = ROW # 二进制日志格式(ROW/STATEMENT/MIXED)binlog_expire_logs_seconds = 604800 # binlog保留时间(秒,7天)max_binlog_size = 1G # 单个binlog文件最大大小sync_binlog = 1 # binlog同步频率(0最快,1最安全)
# ============ 复制配置 ============server-id = 1 # 服务器ID,主从复制环境中必须唯一gtid_mode = ON # 启用GTIDenforce_gtid_consistency = ON # 强制GTID一致性log_slave_updates = ON # 从库是否记录复制的binlog
# ============ 性能优化配置 ============skip_name_resolve = ON # 跳过DNS解析,提高连接速度sql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION # SQL模式transaction_isolation = REPEATABLE-READ # 事务隔离级别query_cache_type = 0 # MySQL 8.0已移除Query Cachetable_open_cache = 2000 # 表缓存数量table_open_cache_instances = 16 # 表缓存实例数open_files_limit = 10000 # 最大打开文件数thread_cache_size = 64 # 线程缓存大小tmp_table_size = 64M # 内存临时表大小max_heap_table_size = 64M # 内存表最大大小
# ============ 安全配置 ============# local_infile = OFF # 禁用LOAD DATA LOCAL INFILE# secure_file_priv = /data/mysql/secure # 限制导入导出文件路径
[mysql]default-character-set = utf8mb4
[mysqldump]max_allowed_packet = 64Mdefault-character-set = utf8mb4关键参数说明
- innodb_buffer_pool_size:最重要的参数,建议设置为物理内存的50%-70%
- innodb_flush_log_at_trx_commit:控制数据安全性和性能的平衡
- 0:每秒刷新一次(最快但可能丢失1秒数据)
- 1:每次事务提交刷新(最安全但最慢,默认值)
- 2:每次事务提交写入OS缓存,每秒刷盘(折中方案)
- max_connections:根据实际并发量设置,过大会消耗过多内存
系统层面优化(Linux)
#!/bin/bash# MySQL服务器系统层面优化脚本
# 1. 修改文件句柄限制cat >> /etc/security/limits.conf << 'EOF'mysql soft nofile 65535mysql hard nofile 65535mysql soft nproc 65535mysql hard nproc 65535EOF
# 2. 修改内核参数cat >> /etc/sysctl.conf << 'EOF'# MySQL优化参数vm.swappiness = 10 # 降低swap使用net.ipv4.ip_local_port_range = 10000 65535 # 扩大端口范围net.ipv4.tcp_max_syn_backlog = 4096 # SYN队列长度net.core.somaxconn = 4096 # socket监听队列长度net.ipv4.tcp_fin_timeout = 30 # TIME_WAIT超时时间net.ipv4.tcp_keepalive_time = 300 # TCP keepalive时间net.ipv4.tcp_tw_reuse = 1 # 复用TIME_WAIT连接EOF
sysctl -p
# 3. 设置IO调度算法(SSD使用noop或deadline,机械盘使用deadline)echo deadline > /sys/block/sda/queue/scheduler
# 4. 关闭transparent_hugepage(透明大页)echo never > /sys/kernel/mm/transparent_hugepage/enabledecho never > /sys/kernel/mm/transparent_hugepage/defrag
# 永久生效(添加到rc.local)cat >> /etc/rc.local << 'EOF'echo never > /sys/kernel/mm/transparent_hugepage/enabledecho never > /sys/kernel/mm/transparent_hugepage/defragEOFchmod +x /etc/rc.local
# 5. 配置numa(如果是多NUMA节点服务器)numactl --interleave=all mysqld_safe &1.3 用户权限与安全管理
数据库安全是运维工作的重中之重,一旦数据库被入侵,后果不堪设想。
用户管理最佳实践
-- 1. 创建应用专用用户(限制IP段访问)CREATE USER 'appuser'@'192.168.1.%'IDENTIFIED WITH mysql_native_password BY 'AppUser@2026!Strong';
-- 2. 创建只读用户(用于报表查询)CREATE USER 'readonly'@'10.0.%.%'IDENTIFIED BY 'ReadOnly@2026!';
-- 3. 创建备份专用用户CREATE USER 'backup'@'localhost'IDENTIFIED BY 'Backup@2026!';
-- 4. 授予应用用户基本权限(遵循最小权限原则)GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'appuser'@'192.168.1.%';
-- 5. 授予只读用户查询权限GRANT SELECT ON myapp.* TO 'readonly'@'10.0.%.%';
-- 6. 授予备份用户必要权限GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER, RELOADON *.* TO 'backup'@'localhost';
-- 7. 刷新权限表FLUSH PRIVILEGES;
-- 8. 查看用户权限SHOW GRANTS FOR 'appuser'@'192.168.1.%';SHOW GRANTS FOR 'readonly'@'10.0.%.%';
-- 9. 撤销权限示例REVOKE DELETE ON myapp.* FROM 'appuser'@'192.168.1.%';
-- 10. 修改用户密码ALTER USER 'appuser'@'192.168.1.%' IDENTIFIED BY 'NewPassword@2026!';
-- 11. 设置密码过期时间(90天)ALTER USER 'appuser'@'192.168.1.%' PASSWORD EXPIRE INTERVAL 90 DAY;
-- 12. 锁定用户ALTER USER 'suspicious_user'@'%' ACCOUNT LOCK;
-- 13. 解锁用户ALTER USER 'suspicious_user'@'%' ACCOUNT UNLOCK;
-- 14. 删除用户DROP USER 'olduser'@'%';密码策略配置
-- 查看密码验证组件SHOW VARIABLES LIKE 'validate_password%';
-- 设置密码策略-- LOW: 只检查密码长度-- MEDIUM: 检查长度、数字、大小写、特殊字符-- STRONG: 检查长度、数字、大小写、特殊字符、字典文件SET GLOBAL validate_password.policy = 'MEDIUM';
-- 设置密码最小长度SET GLOBAL validate_password.length = 12;
-- 设置密码必须包含的数字个数SET GLOBAL validate_password.number_count = 2;
-- 设置密码必须包含的小写字母个数SET GLOBAL validate_password.mixed_case_count = 1;
-- 设置密码必须包含的特殊字符个数SET GLOBAL validate_password.special_char_count = 1;生产环境安全准则
- 禁止使用root用户直接连接应用:为每个应用创建专用数据库用户
- 禁止使用
%通配符:精确限制访问来源IP或网段- 启用SSL加密连接:保护数据传输安全
- 定期审计用户权限:每季度检查一次用户权限,删除无用账号
- 启用审计日志:记录所有敏感操作
SSL加密连接配置
# 1. 生成SSL证书cd /data/mysql/sslopenssl genrsa 2048 > ca-key.pemopenssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca-cert.pemopenssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-req.pemopenssl rsa -in server-key.pem -out server-key.pemopenssl x509 -req -in server-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
# 2. 在my.cnf中配置SSLcat >> /etc/my.cnf << 'EOF'[mysqld]ssl_ca = /data/mysql/ssl/ca-cert.pemssl_cert = /data/mysql/ssl/server-cert.pemssl_key = /data/mysql/ssl/server-key.pemrequire_secure_transport = ONEOF
# 3. 重启MySQLsystemctl restart mysqld-- 创建要求SSL连接的用户CREATE USER 'secureuser'@'%'IDENTIFIED BY 'SecurePass@2026!'REQUIRE SSL;
-- 修改现有用户要求SSLALTER USER 'appuser'@'192.168.1.%' REQUIRE SSL;
-- 验证SSL连接状态SHOW STATUS LIKE 'Ssl_cipher';\s1.4 备份与恢复
备份是数据安全的最后一道防线,没有经过恢复测试的备份等于没有备份。
备份策略对比
| 备份方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| mysqldump逻辑备份 | 灵活、可读、跨平台 | 速度慢、恢复慢、锁表 | 小型数据库、开发测试 |
| xtrabackup物理备份 | 快速、热备、增量 | 依赖存储引擎、版本兼容性 | 大型生产数据库 |
| LVM快照备份 | 快速、几乎无锁 | 需要LVM、恢复复杂 | 特定场景 |
| 云厂商快照备份 | 简单、可靠 | 依赖云平台 | 云上数据库 |
| 主从复制 | 实时、高可用 | 不是真正的备份 | 配合其他备份方式 |
mysqldump逻辑备份详解
#!/bin/bash# MySQL自动备份脚本# 作者: 运维团队# 功能: 每日全量备份+自动清理过期备份
# 配置变量BACKUP_DIR="/data/backup/mysql"MYSQL_USER="backup"MYSQL_PASSWORD="Backup@2026!"MYSQL_HOST="localhost"RETENTION_DAYS=7DATE=$(date +%Y%m%d_%H%M%S)LOG_FILE="/var/log/mysql_backup.log"
# 创建备份目录mkdir -p $BACKUP_DIR
# 备份所有数据库(排除系统库)echo "[$(date)] 开始备份MySQL数据库..." >> $LOG_FILE
mysql -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASSWORD \ -e "SHOW DATABASES;" | grep -Ev "Database|information_schema|performance_schema|mysql|sys" | \while read dbname; do echo "[$(date)] 备份数据库: $dbname" >> $LOG_FILE
mysqldump -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASSWORD \ --single-transaction \ --routines \ --triggers \ --events \ --hex-blob \ --quick \ --max_allowed_packet=512M \ --default-character-set=utf8mb4 \ $dbname | gzip > $BACKUP_DIR/${dbname}_${DATE}.sql.gz
if [ $? -eq 0 ]; then echo "[$(date)] 备份成功: $dbname" >> $LOG_FILE else echo "[$(date)] 备份失败: $dbname" >> $LOG_FILE # 发送告警邮件或钉钉通知 fidone
# 删除过期备份echo "[$(date)] 清理过期备份文件..." >> $LOG_FILEfind $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
echo "[$(date)] 备份任务完成" >> $LOG_FILE# 1. 解压备份文件gunzip myapp_20260519_030000.sql.gz
# 2. 创建数据库(如果不存在)mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS myapp DEFAULT CHARACTER SET utf8mb4;"
# 3. 恢复数据mysql -uroot -p myapp < myapp_20260519_030000.sql
# 4. 验证恢复结果mysql -uroot -p -e "USE myapp; SHOW TABLES; SELECT COUNT(*) FROM users;"Percona XtraBackup物理备份(推荐)
#!/bin/bash# XtraBackup全量备份脚本
BACKUP_DIR="/data/backup/xtrabackup"MYSQL_USER="backup"MYSQL_PASSWORD="Backup@2026!"DATE=$(date +%Y%m%d_%H%M%S)FULL_BACKUP_DIR="$BACKUP_DIR/full/$DATE"
# 创建备份目录mkdir -p $FULL_BACKUP_DIR
# 执行全量备份xtrabackup --user=$MYSQL_USER --password=$MYSQL_PASSWORD \ --backup \ --target-dir=$FULL_BACKUP_DIR \ --parallel=4 \ --compress \ --compress-threads=4
# 检查备份是否成功if [ $? -eq 0 ]; then echo "全量备份成功: $FULL_BACKUP_DIR" # 可以在这里添加备份文件上传到对象存储的逻辑else echo "全量备份失败" exit 1fi#!/bin/bash# XtraBackup增量备份脚本
BACKUP_DIR="/data/backup/xtrabackup"MYSQL_USER="backup"MYSQL_PASSWORD="Backup@2026!"DATE=$(date +%Y%m%d_%H%M%S)FULL_BACKUP_DIR="/data/backup/xtrabackup/full/20260519_030000"INC_BACKUP_DIR="$BACKUP_DIR/inc/$DATE"
# 创建增量备份目录mkdir -p $INC_BACKUP_DIR
# 执行增量备份(基于最新的全量备份)xtrabackup --user=$MYSQL_USER --password=$MYSQL_PASSWORD \ --backup \ --target-dir=$INC_BACKUP_DIR \ --incremental-basedir=$FULL_BACKUP_DIR \ --parallel=4 \ --compress \ --compress-threads=4
if [ $? -eq 0 ]; then echo "增量备份成功: $INC_BACKUP_DIR"else echo "增量备份失败" exit 1fi#!/bin/bash# XtraBackup恢复脚本
FULL_BACKUP_DIR="/data/backup/xtrabackup/full/20260519_030000"INC1_BACKUP_DIR="/data/backup/xtrabackup/inc/20260519_090000"INC2_BACKUP_DIR="/data/backup/xtrabackup/inc/20260519_150000"MYSQL_DATADIR="/data/mysql/data"
# 1. 停止MySQL服务systemctl stop mysqld
# 2. 解压备份文件(如果使用了压缩)xtrabackup --decompress --target-dir=$FULL_BACKUP_DIRxtrabackup --decompress --target-dir=$INC1_BACKUP_DIRxtrabackup --decompress --target-dir=$INC2_BACKUP_DIR
# 3. 准备全量备份xtrabackup --prepare --apply-log-only --target-dir=$FULL_BACKUP_DIR
# 4. 应用第一个增量备份xtrabackup --prepare --apply-log-only \ --target-dir=$FULL_BACKUP_DIR \ --incremental-dir=$INC1_BACKUP_DIR
# 5. 应用第二个增量备份(最后一个增量不加--apply-log-only)xtrabackup --prepare \ --target-dir=$FULL_BACKUP_DIR \ --incremental-dir=$INC2_BACKUP_DIR
# 6. 备份当前数据目录mv $MYSQL_DATADIR ${MYSQL_DATADIR}.old
# 7. 恢复数据xtrabackup --copy-back --target-dir=$FULL_BACKUP_DIR
# 8. 修改权限chown -R mysql:mysql $MYSQL_DATADIR
# 9. 启动MySQLsystemctl start mysqld
# 10. 验证恢复mysql -uroot -p -e "SHOW DATABASES; SELECT NOW();"备份恢复最佳实践
- 定期测试恢复流程:每月至少进行一次完整的恢复演练
- 异地存储备份:备份文件必须存储在与数据库不同的物理位置
- 监控备份任务:使用监控工具监控备份任务执行状态
- 保留多版本备份:至少保留最近7天的全量备份和30天的增量备份
- 记录备份日志:详细记录每次备份的时间、大小、位置等信息
时间点恢复(Point-In-Time Recovery)
# 场景:误删除数据,需要恢复到删除前的状态
# 1. 确定binlog文件和位置# 假设误删除发生在2026-05-19 14:30:00
# 2. 恢复最近的全量备份mysql -uroot -p myapp < myapp_backup_20260519.sql
# 3. 查看binlog文件列表mysqlbinlog --base64-output=decode-rows -v /data/mysql/logs/mysql-bin.000010 | less
# 4. 找到误删除语句的位置(假设是position 12345)
# 5. 恢复误删除之前的binlogmysqlbinlog --start-position=4 --stop-position=12345 \ /data/mysql/logs/mysql-bin.000010 | mysql -uroot -p myapp
# 6. 如果跨越多个binlog文件mysqlbinlog --start-position=4 /data/mysql/logs/mysql-bin.000009 | mysql -uroot -p myappmysqlbinlog --stop-position=12345 /data/mysql/logs/mysql-bin.000010 | mysql -uroot -p myapp
# 7. 或者使用时间戳恢复mysqlbinlog --start-datetime="2026-05-19 14:00:00" \ --stop-datetime="2026-05-19 14:29:59" \ /data/mysql/logs/mysql-bin.* | mysql -uroot -p myapp1.5 性能监控与调优
数据库性能直接影响业务体验,运维人员需要能够及时发现性能问题并进行优化。
性能监控指标体系
系统层面监控
#!/bin/bash# MySQL服务器性能监控脚本
echo "========== CPU使用率 =========="top -bn1 | grep "Cpu(s)" | awk '{print "CPU使用率: " 100 - $8 "%"}'
echo ""echo "========== 内存使用情况 =========="free -h
echo ""echo "========== 磁盘IO统计 =========="iostat -x 1 3
echo ""echo "========== MySQL进程资源使用 =========="ps aux | grep mysqld | grep -v grepMySQL层面监控
-- 1. 查看连接数统计SHOW STATUS LIKE 'Threads_connected'; -- 当前连接数SHOW STATUS LIKE 'Threads_running'; -- 正在运行的线程数SHOW STATUS LIKE 'Max_used_connections'; -- 最大连接数峰值SHOW VARIABLES LIKE 'max_connections'; -- 最大连接数配置
-- 2. 查看QPS和TPSSHOW GLOBAL STATUS LIKE 'Questions'; -- 总查询数SHOW GLOBAL STATUS LIKE 'Com_select'; -- SELECT查询数SHOW GLOBAL STATUS LIKE 'Com_insert'; -- INSERT查询数SHOW GLOBAL STATUS LIKE 'Com_update'; -- UPDATE查询数SHOW GLOBAL STATUS LIKE 'Com_delete'; -- DELETE查询数SHOW GLOBAL STATUS LIKE 'Com_commit'; -- 提交事务数SHOW GLOBAL STATUS LIKE 'Com_rollback'; -- 回滚事务数
-- 3. 查看缓冲池使用情况SHOW STATUS LIKE 'Innodb_buffer_pool_pages%';SHOW STATUS LIKE 'Innodb_buffer_pool_read%';SELECT (1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)) * 100 AS buffer_pool_hit_rateFROM ( SELECT VARIABLE_VALUE AS Innodb_buffer_pool_reads FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') AS t1,( SELECT VARIABLE_VALUE AS Innodb_buffer_pool_read_requests FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests') AS t2;
-- 4. 查看锁等待情况SELECT * FROM performance_schema.data_locks;SELECT * FROM performance_schema.data_lock_waits;SHOW ENGINE INNODB STATUS\G
-- 5. 查看表锁情况SHOW OPEN TABLES WHERE In_use > 0;
-- 6. 查看死锁信息SHOW ENGINE INNODB STATUS\G -- 查看LATEST DETECTED DEADLOCK部分实时性能监控工具
-- MySQL 8.0 性能监控视图SELECT -- 连接信息 (SELECT COUNT(*) FROM performance_schema.threads WHERE TYPE='FOREGROUND') AS current_connections, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Max_used_connections') AS max_used_connections, (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME='max_connections') AS max_connections,
-- QPS统计 (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Questions') AS total_questions, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Com_select') AS total_selects, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Com_insert') AS total_inserts, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Com_update') AS total_updates, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Com_delete') AS total_deletes,
-- 缓冲池统计 (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_read_requests') AS buffer_pool_read_requests, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_reads') AS buffer_pool_reads, ROUND((1 - ( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_reads') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_read_requests') )) * 100, 2) AS buffer_pool_hit_rate_pct\G推荐监控工具
- Prometheus + Grafana + mysqld_exporter:开源监控解决方案
- PMM (Percona Monitoring and Management):专业MySQL监控工具
- Zabbix:企业级监控平台
- DataDog/New Relic:云端监控服务
- pt-tools:Percona Toolkit工具集
1.6 高可用架构设计
在生产环境中,单点故障是不可接受的,你需要设计和维护MySQL高可用架构。
主从复制架构配置
-- 1. 修改主库配置文件 /etc/my.cnf-- [mysqld]-- server-id = 1-- log_bin = /data/mysql/logs/mysql-bin-- binlog_format = ROW-- gtid_mode = ON-- enforce_gtid_consistency = ON-- log_slave_updates = ON
-- 2. 创建复制用户CREATE USER 'repl'@'192.168.1.%'IDENTIFIED WITH mysql_native_password BY 'Repl@2026!Strong';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%';FLUSH PRIVILEGES;
-- 3. 查看主库状态SHOW MASTER STATUS\G-- 1. 修改从库配置文件 /etc/my.cnf-- [mysqld]-- server-id = 2-- relay_log = /data/mysql/logs/mysql-relay-bin-- read_only = ON-- super_read_only = ON-- gtid_mode = ON-- enforce_gtid_consistency = ON-- log_slave_updates = ON
-- 2. 配置主从复制(使用GTID)STOP SLAVE;
CHANGE MASTER TO MASTER_HOST='192.168.1.100', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='Repl@2026!Strong', MASTER_AUTO_POSITION=1; -- 使用GTID自动定位
START SLAVE;
-- 3. 查看从库状态SHOW SLAVE STATUS\G
-- 重点检查以下字段:-- Slave_IO_Running: Yes-- Slave_SQL_Running: Yes-- Seconds_Behind_Master: 0或很小的值-- Last_IO_Error: 空-- Last_SQL_Error: 空主从复制故障排查
-- 1. 主从延迟过大SHOW SLAVE STATUS\G
-- 查看延迟原因-- 可能原因:-- a) 从库配置低于主库-- b) 从库有大量查询占用资源-- c) 网络延迟-- d) 主库写入压力过大
-- 解决方案:-- 升级从库硬件、优化查询、启用并行复制
-- 2. 主从复制中断SHOW SLAVE STATUS\G-- 查看Last_IO_Error和Last_SQL_Error
-- 如果是SQL线程错误,可以跳过错误事务(慎用)SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;START SLAVE;
-- 或者使用GTID跳过错误事务STOP SLAVE;SET GTID_NEXT='错误事务的GTID';BEGIN;COMMIT;SET GTID_NEXT='AUTOMATIC';START SLAVE;
-- 3. 主从数据不一致-- 使用pt-table-checksum检查数据一致性-- pt-table-checksum --host=主库IP --replicate=test.checksums
-- 使用pt-table-sync修复数据不一致-- pt-table-sync --execute --sync-to-master 从库IPMHA高可用方案
# /etc/mha/app1.cnf[server default]# MySQL用户和密码user=mhapassword=MHA@2026!ssh_user=root
# MHA工作目录manager_workdir=/var/log/mha/app1manager_log=/var/log/mha/app1/manager.logremote_workdir=/var/log/mha/app1
# 复制用户repl_user=replrepl_password=Repl@2026!Strong
# 监控间隔ping_interval=3ping_type=CONNECT
# 主库切换脚本master_ip_failover_script=/usr/local/bin/master_ip_failovershutdown_script=""
[server1]hostname=192.168.1.100port=3306candidate_master=1check_repl_delay=0
[server2]hostname=192.168.1.101port=3306candidate_master=1check_repl_delay=0
[server3]hostname=192.168.1.102port=3306no_master=11.7 故障排查与应急处理
当数据库出现故障时,运维人员需要能够快速定位问题并恢复服务。
常见故障场景与处理
-- 查看当前连接数SHOW STATUS LIKE 'Threads_connected';SHOW VARIABLES LIKE 'max_connections';
-- 查看所有连接详情SHOW FULL PROCESSLIST;
-- 找出长时间Sleep的连接SELECT id, user, host, db, command, time, state, infoFROM information_schema.processlistWHERE command = 'Sleep' AND time > 300ORDER BY time DESC;
-- 杀掉空闲连接(批量kill)SELECT CONCAT('KILL ', id, ';') AS kill_cmdFROM information_schema.processlistWHERE command = 'Sleep' AND time > 300;
-- 临时增加最大连接数(重启后失效)SET GLOBAL max_connections = 1000;
-- 优化wait_timeout参数(自动断开空闲连接)SET GLOBAL wait_timeout = 300;SET GLOBAL interactive_timeout = 300;-- 查看正在执行的查询SHOW FULL PROCESSLIST;
-- 查找耗时最长的查询SELECT id, user, host, db, command, time, state, LEFT(info, 100) AS query_previewFROM information_schema.processlistWHERE command != 'Sleep'ORDER BY time DESCLIMIT 10;
-- 杀掉慢查询KILL QUERY 进程ID; -- 只杀查询,不断开连接KILL 进程ID; -- 杀进程并断开连接
-- 分析慢查询日志-- pt-query-digest /var/log/mysql/slow.log
-- 使用EXPLAIN分析SQLEXPLAIN SELECT ...;# 1. 查看错误日志tail -100 /data/mysql/logs/error.log
# 常见启动失败原因:# a) 端口被占用netstat -tunlp | grep 3306lsof -i:3306
# b) 数据目录权限问题ls -la /data/mysql/datachown -R mysql:mysql /data/mysql
# c) 配置文件错误mysqld --help --verbose | grep my.cnfmysqld --validate-config
# d) InnoDB数据损坏# 在my.cnf中添加innodb_force_recovery = 1 # 1-6,级别越高恢复力度越大,但数据丢失风险越高
# e) 磁盘空间不足df -hdu -sh /data/mysql/*
# 2. 尝试安全模式启动mysqld_safe --skip-grant-tables --skip-networking &
# 3. 查看系统日志journalctl -xe | grep mysqldmesg | grep -i mysql-- 查看从库状态SHOW SLAVE STATUS\G
-- 场景1:主库binlog被清理导致同步中断-- 需要重新搭建主从复制-- 1) 在主库做全量备份-- 2) 恢复到从库-- 3) 重新配置主从复制
-- 场景2:SQL线程错误(数据冲突)-- 方法1:跳过错误(谨慎使用)STOP SLAVE;SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;START SLAVE;
-- 方法2:手动修复数据后重启复制STOP SLAVE;-- 手动修复数据...START SLAVE;
-- 场景3:IO线程错误(网络问题)STOP SLAVE IO_THREAD;START SLAVE IO_THREAD;
-- 场景4:主从数据不一致-- 使用pt-table-checksum + pt-table-sync工具修复二、MySQL常用指令详解与实战
2.1 连接与退出指令
# 1. 基本连接方式mysql -u用户名 -p
# 2. 连接指定主机和端口mysql -h192.168.1.100 -P3306 -uroot -p
# 3. 连接时指定数据库mysql -h192.168.1.100 -uroot -p myapp
# 4. 使用SSL加密连接mysql -h192.168.1.100 -uroot -p --ssl-mode=REQUIRED
# 5. 使用socket文件连接(本地连接更快)mysql -uroot -p --socket=/tmp/mysql.sock
# 6. 执行SQL语句后立即退出mysql -uroot -p -e "SHOW DATABASES;"
# 7. 从文件读取SQL并执行mysql -uroot -p < backup.sql
# 8. 使用配置文件存储密码(避免明文密码)cat > ~/.my.cnf << 'EOF'[client]user=rootpassword=YourPasswordhost=localhostEOFchmod 600 ~/.my.cnfmysql # 直接连接,无需输入密码密码安全绝不要在命令行中使用
-p密码的方式输入密码,因为密码会被记录在shell历史中。应该使用以下安全方式:
- 使用
-p后回车输入密码- 使用
~/.my.cnf配置文件- 使用环境变量
MYSQL_PWD(不推荐)
-- 方式1(推荐)exit;
-- 方式2quit;
-- 方式3\q
-- Ctrl + D 快捷键2.2 数据库操作指令
-- 1. 查看所有数据库SHOW DATABASES;
-- 2. 查看数据库创建语句SHOW CREATE DATABASE myapp\G
-- 3. 创建数据库(生产环境标准写法)CREATE DATABASE IF NOT EXISTS myappDEFAULT CHARACTER SET utf8mb4DEFAULT COLLATE utf8mb4_unicode_ci;
-- 4. 修改数据库字符集ALTER DATABASE myappCHARACTER SET utf8mb4COLLATE utf8mb4_unicode_ci;
-- 5. 删除数据库(危险操作,需谨慎)DROP DATABASE IF EXISTS old_database;
-- 6. 切换数据库USE myapp;
-- 7. 查看当前所在数据库SELECT DATABASE();
-- 8. 查看数据库大小SELECT table_schema AS 'Database', ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)'FROM information_schema.tablesWHERE table_schema = 'myapp'GROUP BY table_schema;2.3 表操作指令
-- 1. 查看所有表SHOW TABLES;
-- 2. 查看表结构(多种方式)DESC users;DESCRIBE users;SHOW COLUMNS FROM users;
-- 3. 查看表的详细创建语句SHOW CREATE TABLE users\G
-- 4. 查看表的索引信息SHOW INDEX FROM users;
-- 5. 查看表的统计信息SHOW TABLE STATUS LIKE 'users'\G
-- 6. 创建表(完整示例)CREATE TABLE IF NOT EXISTS users ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID', username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名', email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱', password VARCHAR(255) NOT NULL COMMENT '密码哈希', nickname VARCHAR(50) DEFAULT NULL COMMENT '昵称', avatar VARCHAR(255) DEFAULT NULL COMMENT '头像URL', status TINYINT DEFAULT 1 COMMENT '状态:0禁用 1正常', last_login_at TIMESTAMP NULL DEFAULT NULL COMMENT '最后登录时间', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', INDEX idx_status (status), INDEX idx_created_at (created_at), INDEX idx_last_login (last_login_at)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
-- 7. 复制表结构(不复制数据)CREATE TABLE users_backup LIKE users;
-- 8. 复制表结构和数据CREATE TABLE users_backup AS SELECT * FROM users;
-- 9. 修改表结构 - 添加列ALTER TABLE usersADD COLUMN phone VARCHAR(20) DEFAULT NULL COMMENT '手机号'AFTER email;
-- 10. 修改表结构 - 删除列ALTER TABLE users DROP COLUMN old_column;
-- 11. 修改表结构 - 修改列类型ALTER TABLE usersMODIFY COLUMN nickname VARCHAR(100) DEFAULT NULL COMMENT '昵称';
-- 12. 修改表结构 - 修改列名和类型ALTER TABLE usersCHANGE COLUMN old_name new_name VARCHAR(50) DEFAULT NULL COMMENT '新字段';
-- 13. 添加主键ALTER TABLE users ADD PRIMARY KEY (id);
-- 14. 删除主键ALTER TABLE users DROP PRIMARY KEY;
-- 15. 添加索引ALTER TABLE users ADD INDEX idx_username (username);ALTER TABLE users ADD UNIQUE INDEX uniq_email (email);ALTER TABLE users ADD FULLTEXT INDEX ft_nickname (nickname);
-- 16. 删除索引ALTER TABLE users DROP INDEX idx_username;
-- 17. 添加外键约束ALTER TABLE ordersADD CONSTRAINT fk_user_idFOREIGN KEY (user_id) REFERENCES users(id)ON DELETE CASCADE ON UPDATE CASCADE;
-- 18. 删除外键约束ALTER TABLE orders DROP FOREIGN KEY fk_user_id;
-- 19. 修改表名ALTER TABLE users RENAME TO app_users;RENAME TABLE app_users TO users;
-- 20. 修改表引擎ALTER TABLE users ENGINE = InnoDB;
-- 21. 优化表(整理碎片)OPTIMIZE TABLE users;
-- 22. 分析表(更新索引统计信息)ANALYZE TABLE users;
-- 23. 检查表完整性CHECK TABLE users;
-- 24. 修复表REPAIR TABLE users;
-- 25. 删除表DROP TABLE IF EXISTS old_table;
-- 26. 清空表(保留表结构)TRUNCATE TABLE users; -- 快速,无法回滚DELETE FROM users; -- 慢,可以回滚表结构设计最佳实践
- 主键设计:优先使用自增整数作为主键,避免使用UUID(占用空间大)
- 字符集选择:统一使用
utf8mb4字符集,支持emoji等特殊字符- 字段命名:使用蛇形命名法(snake_case),避免使用MySQL保留字
- 合理使用NULL:尽量避免NULL字段,使用默认值代替
- 时间字段:使用
TIMESTAMP或DATETIME,配合DEFAULT CURRENT_TIMESTAMP- 添加注释:为表和字段添加详细的
COMMENT
2.4 数据操作指令
-- ================ 插入数据 ================
-- 1. 插入单行数据INSERT INTO users (username, email, password)VALUES ('zhangsan', 'zhangsan@example.com', 'hashed_password_123');
-- 2. 插入多行数据(高效)INSERT INTO users (username, email, password, nickname)VALUES ('lisi', 'lisi@example.com', 'hashed_pwd_456', '李四'), ('wangwu', 'wangwu@example.com', 'hashed_pwd_789', '王五'), ('zhaoliu', 'zhaoliu@example.com', 'hashed_pwd_012', '赵六');
-- 3. 插入时忽略重复数据INSERT IGNORE INTO users (username, email, password)VALUES ('zhangsan', 'zhangsan@example.com', 'new_password');
-- 4. 插入时如果重复则更新INSERT INTO users (username, email, password)VALUES ('zhangsan', 'zhangsan@example.com', 'new_password')ON DUPLICATE KEY UPDATE password = VALUES(password), updated_at = CURRENT_TIMESTAMP;
-- 5. 从另一个表插入数据INSERT INTO users_backup (username, email, password)SELECT username, email, password FROM users WHERE status = 1;
-- 6. 批量插入优化(使用事务)START TRANSACTION;INSERT INTO users (username, email, password) VALUES (...);INSERT INTO users (username, email, password) VALUES (...);-- ... 更多插入COMMIT;
-- ================ 查询数据 ================
-- 7. 基本查询SELECT * FROM users;SELECT id, username, email FROM users;
-- 8. 条件查询SELECT * FROM users WHERE status = 1;SELECT * FROM users WHERE username = 'zhangsan' AND status = 1;SELECT * FROM users WHERE username IN ('zhangsan', 'lisi', 'wangwu');SELECT * FROM users WHERE username LIKE 'zhang%';SELECT * FROM users WHERE created_at BETWEEN '2026-01-01' AND '2026-12-31';SELECT * FROM users WHERE email IS NOT NULL;
-- 9. 排序查询SELECT * FROM users ORDER BY created_at DESC;SELECT * FROM users ORDER BY status ASC, created_at DESC;
-- 10. 分页查询(重要)SELECT * FROM users LIMIT 20; -- 只取前20条SELECT * FROM users LIMIT 20 OFFSET 40; -- 跳过40条,取20条SELECT * FROM users LIMIT 40, 20; -- 等同于上面
-- 11. 聚合查询SELECT COUNT(*) FROM users;SELECT COUNT(DISTINCT username) FROM users;SELECT SUM(amount), AVG(amount), MAX(amount), MIN(amount) FROM orders;
-- 12. 分组查询SELECT status, COUNT(*) AS user_countFROM usersGROUP BY status;
SELECT DATE(created_at) AS date, COUNT(*) AS daily_usersFROM usersGROUP BY DATE(created_at)ORDER BY date DESC;
-- 13. HAVING子句(对分组结果进行过滤)SELECT status, COUNT(*) AS user_countFROM usersGROUP BY statusHAVING user_count > 100;
-- 14. 连接查询-- INNER JOINSELECT u.username, o.order_no, o.amountFROM users uINNER JOIN orders o ON u.id = o.user_id;
-- LEFT JOINSELECT u.username, o.order_no, o.amountFROM users uLEFT JOIN orders o ON u.id = o.user_id;
-- RIGHT JOINSELECT u.username, o.order_no, o.amountFROM users uRIGHT JOIN orders o ON u.id = o.user_id;
-- 15. 子查询SELECT * FROM usersWHERE id IN (SELECT user_id FROM orders WHERE amount > 1000);
SELECT * FROM users uWHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
-- 16. UNION查询(合并多个查询结果)SELECT username FROM users WHERE status = 1UNIONSELECT username FROM users_backup WHERE status = 1;
-- 17. 去重查询SELECT DISTINCT status FROM users;
-- 18. 计算字段SELECT username, CONCAT(username, '@', email) AS full_info, YEAR(created_at) AS register_year, DATEDIFF(NOW(), created_at) AS days_since_registerFROM users;
-- ================ 更新数据 ================
-- 19. 基本更新(务必加WHERE条件!)UPDATE usersSET password = 'new_hashed_password'WHERE username = 'zhangsan';
-- 20. 批量更新UPDATE usersSET status = 0WHERE last_login_at < DATE_SUB(NOW(), INTERVAL 6 MONTH);
-- 21. 使用计算更新UPDATE usersSET nickname = CONCAT('User_', id)WHERE nickname IS NULL;
-- 22. 多表更新UPDATE users uINNER JOIN orders o ON u.id = o.user_idSET u.total_amount = u.total_amount + o.amountWHERE o.status = 'paid';
-- ================ 删除数据 ================
-- 23. 基本删除(务必加WHERE条件!)DELETE FROM users WHERE id = 999;
-- 24. 批量删除DELETE FROM usersWHERE status = 0 AND last_login_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
-- 25. 使用子查询删除DELETE FROM usersWHERE id IN (SELECT user_id FROM banned_users);
-- 26. 清空表(快速但无法回滚)TRUNCATE TABLE temp_table;数据操作安全提示在生产环境执行UPDATE和DELETE前,必须遵循以下流程:
先执行SELECT:用同样的WHERE条件查询要操作的数据
SELECT * FROM users WHERE status = 0 AND created_at < '2020-01-01';确认数据无误后再执行UPDATE/DELETE
DELETE FROM users WHERE status = 0 AND created_at < '2020-01-01';使用事务保护:对于重要操作,先开启事务测试
START TRANSACTION;DELETE FROM users WHERE ...;SELECT * FROM users; -- 验证结果ROLLBACK; -- 如果不对就回滚-- COMMIT; -- 确认无误后提交定期备份:在执行重要操作前先备份相关表
2.5 用户权限管理指令
-- ================ 用户管理 ================
-- 1. 查看所有用户SELECT user, host, account_locked, password_expiredFROM mysql.user;
-- 2. 查看当前用户SELECT USER(), CURRENT_USER();
-- 3. 创建用户(不同场景)-- 本地用户CREATE USER 'localuser'@'localhost'IDENTIFIED BY 'LocalPass@2026!';
-- 指定IP用户CREATE USER 'appuser'@'192.168.1.100'IDENTIFIED BY 'AppPass@2026!';
-- 指定IP段用户CREATE USER 'appuser'@'192.168.1.%'IDENTIFIED BY 'AppPass@2026!';
-- 任意IP用户(不推荐)CREATE USER 'remoteuser'@'%'IDENTIFIED BY 'RemotePass@2026!';
-- 使用特定认证插件CREATE USER 'nativeuser'@'%'IDENTIFIED WITH mysql_native_password BY 'NativePass@2026!';
-- ================ 权限管理 ================
-- 4. 授予权限(遵循最小权限原则)-- 授予单个数据库的所有权限GRANT ALL PRIVILEGES ON myapp.* TO 'appuser'@'192.168.1.%';
-- 授予特定操作权限GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'appuser'@'192.168.1.%';
-- 授予只读权限GRANT SELECT ON myapp.* TO 'readonly'@'10.0.%.%';
-- 授予单个表的权限GRANT SELECT, UPDATE ON myapp.users TO 'partialuser'@'%';
-- 授予复制权限GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'192.168.1.%';
-- 授予备份权限GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER, RELOADON *.* TO 'backup'@'localhost';
-- 授予管理员权限GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
-- 5. 查看用户权限SHOW GRANTS;SHOW GRANTS FOR 'appuser'@'192.168.1.%';
-- 6. 撤销权限REVOKE DELETE ON myapp.* FROM 'appuser'@'192.168.1.%';REVOKE ALL PRIVILEGES ON *.* FROM 'olduser'@'%';
-- 7. 刷新权限(使权限立即生效)FLUSH PRIVILEGES;
-- ================ 密码管理 ================
-- 8. 修改密码-- 修改当前用户密码ALTER USER USER() IDENTIFIED BY 'NewPassword@2026!';
-- 修改指定用户密码ALTER USER 'appuser'@'192.168.1.%' IDENTIFIED BY 'NewPassword@2026!';
-- 使用SET PASSWORD(老版本语法)SET PASSWORD FOR 'appuser'@'192.168.1.%' = PASSWORD('NewPassword@2026!');
-- 9. 设置密码过期策略-- 设置密码90天后过期ALTER USER 'appuser'@'192.168.1.%' PASSWORD EXPIRE INTERVAL 90 DAY;
-- 设置密码永不过期ALTER USER 'appuser'@'192.168.1.%' PASSWORD EXPIRE NEVER;
-- 使用全局默认策略ALTER USER 'appuser'@'192.168.1.%' PASSWORD EXPIRE DEFAULT;
-- 立即过期(强制用户下次登录时修改密码)ALTER USER 'appuser'@'192.168.1.%' PASSWORD EXPIRE;
-- 10. 查看密码策略SHOW VARIABLES LIKE 'default_password_lifetime';
-- ================ 账户管理 ================
-- 11. 锁定/解锁用户ALTER USER 'suspicious_user'@'%' ACCOUNT LOCK;ALTER USER 'suspicious_user'@'%' ACCOUNT UNLOCK;
-- 12. 限制用户资源使用ALTER USER 'limiteduser'@'%'WITH MAX_QUERIES_PER_HOUR 1000 MAX_UPDATES_PER_HOUR 100 MAX_CONNECTIONS_PER_HOUR 50 MAX_USER_CONNECTIONS 10;
-- 13. 删除用户DROP USER 'olduser'@'%';DROP USER IF EXISTS 'tempuser'@'localhost';
-- ================ 角色管理(MySQL 8.0+) ================
-- 14. 创建角色CREATE ROLE 'app_read', 'app_write', 'app_admin';
-- 15. 给角色授权GRANT SELECT ON myapp.* TO 'app_read';GRANT INSERT, UPDATE, DELETE ON myapp.* TO 'app_write';GRANT ALL PRIVILEGES ON myapp.* TO 'app_admin';
-- 16. 将角色分配给用户GRANT 'app_read' TO 'user1'@'%';GRANT 'app_read', 'app_write' TO 'user2'@'%';
-- 17. 设置默认角色SET DEFAULT ROLE ALL TO 'user1'@'%';
-- 18. 激活角色SET ROLE 'app_read';SET ROLE ALL;
-- 19. 查看角色SELECT * FROM mysql.role_edges;SHOW GRANTS FOR 'app_read';
-- 20. 撤销角色REVOKE 'app_write' FROM 'user1'@'%';
-- 21. 删除角色DROP ROLE 'app_write';2.6 备份与恢复指令
#!/bin/bash# 生产环境MySQL自动备份脚本# 功能:全量备份、增量备份、自动清理、异地传输
# ================ 配置区域 ================BACKUP_ROOT="/data/backup/mysql"MYSQL_USER="backup"MYSQL_PASSWORD="Backup@2026!"MYSQL_HOST="localhost"MYSQL_PORT="3306"RETENTION_DAYS=7DATE=$(date +%Y%m%d_%H%M%S)LOG_FILE="/var/log/mysql_backup.log"
# ================ 函数定义 ================
# 日志函数log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE}
# 备份单个数据库backup_database() { local db_name=$1 local backup_file="$BACKUP_ROOT/daily/${db_name}_${DATE}.sql.gz"
log_message "开始备份数据库: $db_name"
mysqldump -h$MYSQL_HOST -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASSWORD \ --single-transaction \ --routines \ --triggers \ --events \ --hex-blob \ --quick \ --max_allowed_packet=512M \ --default-character-set=utf8mb4 \ --set-gtid-purged=OFF \ $db_name | gzip > $backup_file
if [ $? -eq 0 ]; then local file_size=$(du -sh $backup_file | cut -f1) log_message "备份成功: $db_name (大小: $file_size)" return 0 else log_message "备份失败: $db_name" return 1 fi}
# 清理过期备份cleanup_old_backups() { log_message "开始清理${RETENTION_DAYS}天前的备份文件..." find $BACKUP_ROOT/daily -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete log_message "清理完成"}
# 上传备份到远程服务器(可选)upload_to_remote() { local backup_file=$1 # 使用rsync上传到远程备份服务器 # rsync -avz $backup_file backup@remote-server:/backup/mysql/ # 或者上传到对象存储 # aws s3 cp $backup_file s3://my-backup-bucket/mysql/}
# ================ 主流程 ================
log_message "========== MySQL备份任务开始 =========="
# 创建备份目录mkdir -p $BACKUP_ROOT/daily
# 获取数据库列表(排除系统数据库)databases=$(mysql -h$MYSQL_HOST -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASSWORD \ -e "SHOW DATABASES;" | grep -Ev "Database|information_schema|performance_schema|mysql|sys")
# 备份每个数据库for db in $databases; do backup_database $dbdone
# 清理过期备份cleanup_old_backups
# 备份binlog位置信息mysql -h$MYSQL_HOST -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASSWORD \ -e "SHOW MASTER STATUS\G" > $BACKUP_ROOT/daily/binlog_position_${DATE}.txt
log_message "========== MySQL备份任务完成 =========="
# 发送备份报告邮件(可选)# echo "MySQL备份完成" | mail -s "MySQL Backup Report" admin@example.com# ================ 恢复前准备 ================
# 1. 查看备份文件ls -lh /data/backup/mysql/daily/
# 2. 验证备份文件完整性gzip -t myapp_20260519_030000.sql.gz
# 3. 解压备份文件gunzip myapp_20260519_030000.sql.gz
# ================ 恢复整个数据库 ================
# 4. 删除现有数据库(如果需要完全重建)mysql -uroot -p -e "DROP DATABASE IF EXISTS myapp;"
# 5. 创建新数据库mysql -uroot -p -e "CREATE DATABASE myapp DEFAULT CHARACTER SET utf8mb4;"
# 6. 恢复数据mysql -uroot -p myapp < myapp_20260519_030000.sql
# ================ 恢复单个表 ================
# 7. 从完整备份中提取单个表的SQLsed -n '/CREATE TABLE.*users/,/UNLOCK TABLES/p' myapp_20260519_030000.sql > users_table.sql
# 8. 恢复单个表mysql -uroot -p myapp < users_table.sql
# ================ 时间点恢复 ================
# 9. 先恢复最近的全量备份mysql -uroot -p myapp < myapp_20260519_030000.sql
# 10. 使用binlog进行时间点恢复# 查找binlog文件ls -lh /data/mysql/logs/mysql-bin.*
# 查看binlog内容,找到需要恢复的时间点mysqlbinlog --base64-output=decode-rows -v \ /data/mysql/logs/mysql-bin.000010 | less
# 恢复指定时间段的binlogmysqlbinlog --start-datetime="2026-05-19 14:00:00" \ --stop-datetime="2026-05-19 14:29:59" \ --database=myapp \ /data/mysql/logs/mysql-bin.000010 | mysql -uroot -p myapp
# ================ 验证恢复 ================
# 11. 验证数据完整性mysql -uroot -p myapp -e " SELECT COUNT(*) FROM users; SELECT MAX(id) FROM users; SELECT * FROM users ORDER BY id DESC LIMIT 10;"# ================ 全量备份 ================
#!/bin/bash# XtraBackup自动备份脚本
BACKUP_ROOT="/data/backup/xtrabackup"MYSQL_USER="backup"MYSQL_PASSWORD="Backup@2026!"DATE=$(date +%Y%m%d_%H%M%S)FULL_BACKUP_DIR="$BACKUP_ROOT/full/$DATE"RETENTION_DAYS=7
# 创建备份目录mkdir -p $FULL_BACKUP_DIR
echo "[$(date)] 开始XtraBackup全量备份..."
# 执行全量备份xtrabackup --user=$MYSQL_USER --password=$MYSQL_PASSWORD \ --backup \ --target-dir=$FULL_BACKUP_DIR \ --parallel=4 \ --compress \ --compress-threads=4 \ --stream=xbstream | gzip > $FULL_BACKUP_DIR.tar.gz
if [ $? -eq 0 ]; then rm -rf $FULL_BACKUP_DIR echo "[$(date)] 全量备份成功: $FULL_BACKUP_DIR.tar.gz"
# 清理过期备份 find $BACKUP_ROOT/full -name "*.tar.gz" -mtime +$RETENTION_DAYS -deleteelse echo "[$(date)] 全量备份失败" exit 1fi
# ================ 增量备份 ================
#!/bin/bash# XtraBackup增量备份脚本
BACKUP_ROOT="/data/backup/xtrabackup"MYSQL_USER="backup"MYSQL_PASSWORD="Backup@2026!"DATE=$(date +%Y%m%d_%H%M%S)FULL_BACKUP_BASE="/data/backup/xtrabackup/full/20260519_030000"INC_BACKUP_DIR="$BACKUP_ROOT/inc/$DATE"
mkdir -p $INC_BACKUP_DIR
echo "[$(date)] 开始XtraBackup增量备份..."
# 执行增量备份xtrabackup --user=$MYSQL_USER --password=$MYSQL_PASSWORD \ --backup \ --target-dir=$INC_BACKUP_DIR \ --incremental-basedir=$FULL_BACKUP_BASE \ --parallel=4
if [ $? -eq 0 ]; then echo "[$(date)] 增量备份成功: $INC_BACKUP_DIR"else echo "[$(date)] 增量备份失败" exit 1fi
# ================ XtraBackup恢复 ================
#!/bin/bash# XtraBackup恢复脚本
FULL_BACKUP="/data/backup/xtrabackup/full/20260519_030000.tar.gz"INC_BACKUP_1="/data/backup/xtrabackup/inc/20260519_090000"INC_BACKUP_2="/data/backup/xtrabackup/inc/20260519_150000"RESTORE_DIR="/data/restore/xtrabackup"MYSQL_DATADIR="/data/mysql/data"
echo "[$(date)] 开始XtraBackup恢复流程..."
# 1. 停止MySQLecho "停止MySQL服务..."systemctl stop mysqld
# 2. 解压全量备份echo "解压全量备份..."mkdir -p $RESTORE_DIR/fulltar -izxf $FULL_BACKUP -C $RESTORE_DIR/full
# 3. 解压xbstream格式cd $RESTORE_DIR/fullxbstream -x < $RESTORE_DIR/full/*.xbstream
# 4. 解压备份文件xtrabackup --decompress --target-dir=$RESTORE_DIR/full
# 5. 准备全量备份echo "准备全量备份..."xtrabackup --prepare --apply-log-only --target-dir=$RESTORE_DIR/full
# 6. 应用增量备份1if [ -d "$INC_BACKUP_1" ]; then echo "应用增量备份1..." xtrabackup --prepare --apply-log-only \ --target-dir=$RESTORE_DIR/full \ --incremental-dir=$INC_BACKUP_1fi
# 7. 应用增量备份2(最后一个不加--apply-log-only)if [ -d "$INC_BACKUP_2" ]; then echo "应用增量备份2..." xtrabackup --prepare \ --target-dir=$RESTORE_DIR/full \ --incremental-dir=$INC_BACKUP_2fi
# 8. 备份当前数据目录echo "备份当前数据目录..."mv $MYSQL_DATADIR ${MYSQL_DATADIR}.bak_$(date +%Y%m%d_%H%M%S)
# 9. 恢复数据echo "恢复数据..."xtrabackup --copy-back --target-dir=$RESTORE_DIR/full
# 10. 修改权限echo "修改数据目录权限..."chown -R mysql:mysql $MYSQL_DATADIR
# 11. 启动MySQLecho "启动MySQL服务..."systemctl start mysqld
# 12. 验证echo "验证恢复结果..."sleep 5mysql -uroot -p -e "SHOW DATABASES; SELECT NOW();"
echo "[$(date)] XtraBackup恢复完成!"2.7 性能监控指令
-- ================ 连接与线程监控 ================
-- 1. 查看当前连接数和最大连接数SELECT (SELECT COUNT(*) FROM information_schema.processlist) AS current_connections, (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Max_used_connections') AS max_used_connections, (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME='max_connections') AS max_connections, ROUND( (SELECT COUNT(*) FROM information_schema.processlist) / (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME='max_connections') * 100, 2 ) AS connection_usage_pct;
-- 2. 查看所有连接详情SHOW FULL PROCESSLIST;
-- 3. 查看长时间运行的查询SELECT id, user, host, db, command, time, state, LEFT(info, 100) AS query_previewFROM information_schema.processlistWHERE command != 'Sleep' AND time > 10ORDER BY time DESC;
-- 4. 查看Sleep连接统计SELECT user, COUNT(*) AS sleep_count, AVG(time) AS avg_sleep_time, MAX(time) AS max_sleep_timeFROM information_schema.processlistWHERE command = 'Sleep'GROUP BY userORDER BY sleep_count DESC;
-- ================ QPS/TPS监控 ================
-- 5. 查看各类操作统计SELECT VARIABLE_NAME AS operation, VARIABLE_VALUE AS countFROM performance_schema.global_statusWHERE VARIABLE_NAME IN ( 'Questions', 'Com_select', 'Com_insert', 'Com_update', 'Com_delete', 'Com_commit', 'Com_rollback')ORDER BY VARIABLE_NAME;
-- 6. 计算实时QPS(需要两次采样)-- 第一次采样CREATE TEMPORARY TABLE qps_sample1 ASSELECT VARIABLE_NAME, VARIABLE_VALUE, UNIX_TIMESTAMP() AS sample_timeFROM performance_schema.global_statusWHERE VARIABLE_NAME IN ('Questions', 'Com_select', 'Com_insert', 'Com_update', 'Com_delete');
-- 等待1秒SELECT SLEEP(1);
-- 第二次采样并计算QPSSELECT s2.VARIABLE_NAME, ROUND((s2.VARIABLE_VALUE - s1.VARIABLE_VALUE) / (s2.sample_time - s1.sample_time), 2) AS qpsFROM qps_sample1 s1JOIN ( SELECT VARIABLE_NAME, VARIABLE_VALUE, UNIX_TIMESTAMP() AS sample_time FROM performance_schema.global_status WHERE VARIABLE_NAME IN ('Questions', 'Com_select', 'Com_insert', 'Com_update', 'Com_delete')) s2 ON s1.VARIABLE_NAME = s2.VARIABLE_NAME;
-- ================ 缓冲池监控 ================
-- 7. 查看缓冲池命中率SELECT VARIABLE_NAME, VARIABLE_VALUEFROM performance_schema.global_statusWHERE VARIABLE_NAME IN ( 'Innodb_buffer_pool_read_requests', 'Innodb_buffer_pool_reads', 'Innodb_buffer_pool_pages_total', 'Innodb_buffer_pool_pages_free', 'Innodb_buffer_pool_pages_data', 'Innodb_buffer_pool_pages_dirty');
-- 8. 计算缓冲池命中率SELECT ROUND( (1 - ( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_reads') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_read_requests') )) * 100, 2 ) AS buffer_pool_hit_rate_pct;
-- 9. 查看缓冲池使用详情SELECT ROUND( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_data') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_total') * 100, 2 ) AS data_page_pct, ROUND( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_dirty') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_total') * 100, 2 ) AS dirty_page_pct, ROUND( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_free') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_total') * 100, 2 ) AS free_page_pct;
-- ================ 锁监控 ================
-- 10. 查看当前锁等待SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, r.trx_query AS waiting_query, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, b.trx_query AS blocking_queryFROM information_schema.innodb_lock_waits wINNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_idINNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
-- 11. 查看表锁情况SELECT object_schema AS db, object_name AS table_name, lock_type, lock_mode, lock_status, thread_idFROM performance_schema.data_locksWHERE object_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys');
-- 12. 查看死锁历史(MySQL 8.0+)SELECT * FROM performance_schema.events_statements_historyWHERE errors_count > 0 AND sql_text LIKE '%Deadlock%';
-- ================ 慢查询监控 ================
-- 13. 查看慢查询配置SHOW VARIABLES LIKE 'slow_query_log%';SHOW VARIABLES LIKE 'long_query_time';SHOW VARIABLES LIKE 'log_queries_not_using_indexes';
-- 14. 查看慢查询统计SHOW GLOBAL STATUS LIKE 'Slow_queries';
-- 15. 使用performance_schema分析慢查询SELECT DIGEST_TEXT AS query_pattern, COUNT_STAR AS exec_count, AVG_TIMER_WAIT / 1000000000000 AS avg_time_sec, MAX_TIMER_WAIT / 1000000000000 AS max_time_sec, SUM_ROWS_EXAMINED AS total_rows_examined, SUM_ROWS_SENT AS total_rows_sentFROM performance_schema.events_statements_summary_by_digestORDER BY SUM_TIMER_WAIT DESCLIMIT 20;
-- ================ 表统计监控 ================
-- 16. 查看表大小排行SELECT table_schema AS 'Database', table_name AS 'Table', ROUND((data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)', ROUND(data_length / 1024 / 1024, 2) AS 'Data (MB)', ROUND(index_length / 1024 / 1024, 2) AS 'Index (MB)', table_rows AS 'Rows'FROM information_schema.tablesWHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')ORDER BY (data_length + index_length) DESCLIMIT 20;
-- 17. 查看表的碎片率SELECT table_schema AS 'Database', table_name AS 'Table', ROUND(data_free / 1024 / 1024, 2) AS 'Fragmentation (MB)', ROUND(data_free / (data_length + index_length + data_free) * 100, 2) AS 'Fragmentation (%)'FROM information_schema.tablesWHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') AND (data_length + index_length) > 0 AND data_free > 0ORDER BY data_free DESCLIMIT 20;
-- ================ 复制监控 ================
-- 18. 查看主库复制状态SHOW MASTER STATUS\G
-- 19. 查看从库复制状态SHOW SLAVE STATUS\G
-- 20. 查看从库延迟(秒)SELECT CASE WHEN Seconds_Behind_Master IS NULL THEN 'Not Replicating' ELSE CONCAT(Seconds_Behind_Master, ' seconds') END AS replication_lagFROM ( SHOW SLAVE STATUS) AS slave_status;2.8 其他实用指令
-- ================ 系统信息查询 ================
-- 1. 查看MySQL版本SELECT VERSION();SELECT @@version;
-- 2. 查看服务器状态SHOW STATUS;
-- 3. 查看系统变量SHOW VARIABLES;
-- 4. 查看字符集SHOW VARIABLES LIKE 'character%';SHOW VARIABLES LIKE 'collation%';
-- 5. 查看存储引擎SHOW ENGINES;
-- 6. 查看插件SHOW PLUGINS;
-- 7. 查看当前时间SELECT NOW(), CURDATE(), CURTIME();SELECT UNIX_TIMESTAMP(), FROM_UNIXTIME(UNIX_TIMESTAMP());
-- 8. 查看运行时间SHOW GLOBAL STATUS LIKE 'Uptime';SELECT CONCAT( FLOOR(VARIABLE_VALUE / 86400), ' days ', FLOOR((VARIABLE_VALUE % 86400) / 3600), ' hours' ) AS uptimeFROM performance_schema.global_statusWHERE VARIABLE_NAME = 'Uptime';
-- ================ 数据库大小查询 ================
-- 9. 查看所有数据库大小SELECT table_schema AS 'Database', ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)', ROUND(SUM(data_length) / 1024 / 1024, 2) AS 'Data (MB)', ROUND(SUM(index_length) / 1024 / 1024, 2) AS 'Index (MB)'FROM information_schema.tablesGROUP BY table_schemaORDER BY SUM(data_length + index_length) DESC;
-- 10. 查看指定数据库大小SELECT table_name AS 'Table', ROUND((data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)', table_rows AS 'Rows'FROM information_schema.tablesWHERE table_schema = 'myapp'ORDER BY (data_length + index_length) DESC;
-- ================ 索引分析 ================
-- 11. 查看未使用的索引SELECT object_schema AS database_name, object_name AS table_name, index_nameFROM performance_schema.table_io_waits_summary_by_index_usageWHERE index_name IS NOT NULL AND count_star = 0 AND object_schema NOT IN ('mysql', 'performance_schema', 'sys')ORDER BY object_schema, object_name;
-- 12. 查看重复索引SELECT a.table_schema, a.table_name, a.index_name AS index1, b.index_name AS index2, a.column_nameFROM information_schema.statistics aJOIN information_schema.statistics b ON a.table_schema = b.table_schema AND a.table_name = b.table_name AND a.column_name = b.column_name AND a.seq_in_index = b.seq_in_index AND a.index_name < b.index_nameWHERE a.table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')ORDER BY a.table_schema, a.table_name;
-- ================ 事务管理 ================
-- 13. 开启事务START TRANSACTION;BEGIN;
-- 14. 提交事务COMMIT;
-- 15. 回滚事务ROLLBACK;
-- 16. 设置保存点SAVEPOINT sp1;ROLLBACK TO SAVEPOINT sp1;RELEASE SAVEPOINT sp1;
-- 17. 查看当前事务SELECT * FROM information_schema.innodb_trx\G
-- 18. 查看长时间未提交的事务SELECT trx_id, trx_mysql_thread_id AS thread_id, TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS running_seconds, trx_query AS current_queryFROM information_schema.innodb_trxWHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 60ORDER BY running_seconds DESC;
-- ================ 维护操作 ================
-- 19. 分析表(更新索引统计信息)ANALYZE TABLE users;
-- 20. 优化表(整理碎片)OPTIMIZE TABLE users;
-- 21. 检查表完整性CHECK TABLE users;
-- 22. 修复表REPAIR TABLE users;
-- 23. 刷新表FLUSH TABLES;FLUSH TABLES WITH READ LOCK; -- 加全局读锁UNLOCK TABLES; -- 解锁
-- 24. 刷新日志FLUSH LOGS; -- 刷新所有日志FLUSH BINARY LOGS; -- 刷新binlogFLUSH ERROR LOGS; -- 刷新错误日志FLUSH SLOW LOGS; -- 刷新慢查询日志
-- 25. 清理binlogPURGE BINARY LOGS BEFORE '2026-01-01 00:00:00';PURGE BINARY LOGS TO 'mysql-bin.000100';
-- ================ 导入导出 ================
-- 26. 导出查询结果到CSVSELECT * FROM usersINTO OUTFILE '/tmp/users.csv'FIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n';
-- 27. 从CSV导入数据LOAD DATA INFILE '/tmp/users.csv'INTO TABLE usersFIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n'IGNORE 1 LINES;三、运维人员MySQL进阶技能
3.1 慢查询分析与SQL优化
慢查询是导致数据库性能下降的最常见原因之一。你需要掌握如何分析慢查询日志并优化慢SQL。
开启慢查询日志
[mysqld]# 启用慢查询日志slow_query_log = ONslow_query_log_file = /data/mysql/logs/slow.log
# 慢查询阈值(秒)long_query_time = 2
# 记录未使用索引的查询log_queries_not_using_indexes = ON
# 限制未使用索引日志的记录频率(每分钟最多10条)log_throttle_queries_not_using_indexes = 10
# 记录管理语句(ALTER TABLE等)log_slow_admin_statements = ON
# 记录从库上的慢查询log_slow_slave_statements = ON-- 临时开启(重启后失效)SET GLOBAL slow_query_log = ON;SET GLOBAL long_query_time = 2;SET GLOBAL log_queries_not_using_indexes = ON;
-- 查看配置SHOW VARIABLES LIKE 'slow_query_log%';SHOW VARIABLES LIKE 'long_query_time';
-- 查看慢查询统计SHOW GLOBAL STATUS LIKE 'Slow_queries';分析慢查询日志
# 查看执行次数最多的10条慢查询mysqldumpslow -s c -t 10 /data/mysql/logs/slow.log
# 查看返回记录集最多的10条慢查询mysqldumpslow -s r -t 10 /data/mysql/logs/slow.log
# 查看执行时间最长的10条慢查询mysqldumpslow -s t -t 10 /data/mysql/logs/slow.log
# 查看平均执行时间最长的10条慢查询mysqldumpslow -s at -t 10 /data/mysql/logs/slow.log
# 组合使用:查看访问次数最多的10条慢查询,不区分大小写mysqldumpslow -s c -t 10 -i /data/mysql/logs/slow.log使用pt-query-digest深度分析(推荐)
# 安装percona-toolkityum install percona-toolkit -y
# 分析慢查询日志pt-query-digest /data/mysql/logs/slow.log > slow_query_report.txt
# 只分析最近1小时的日志pt-query-digest --since '1h' /data/mysql/logs/slow.log
# 只分析特定数据库pt-query-digest --filter '($event->{db} || "") eq "myapp"' /data/mysql/logs/slow.log
# 输出为JSON格式pt-query-digest --output json /data/mysql/logs/slow.log > slow.json
# 将分析结果存入数据库pt-query-digest --review h=localhost,D=slow_query_log,t=global_query_review \ --create-review-table /data/mysql/logs/slow.log
# 对比两个日志文件pt-query-digest --review h=localhost,D=slow_query_log,t=global_query_review \ --create-review-table slow1.logpt-query-digest --review h=localhost,D=slow_query_log,t=global_query_review \ --report slow2.logEXPLAIN执行计划分析
-- 基本用法EXPLAIN SELECT * FROM users WHERE username = 'zhangsan';
-- 查看JSON格式输出(更详细)EXPLAIN FORMAT=JSON SELECT * FROM users WHERE username = 'zhangsan'\G
-- 查看实际执行信息(MySQL 8.0.18+)EXPLAIN ANALYZE SELECT * FROM users WHERE username = 'zhangsan'\G
-- 示例1:全表扫描(性能差)EXPLAIN SELECT * FROM users WHERE YEAR(created_at) = 2026;-- type: ALL(全表扫描)-- Extra: Using where
-- 优化后:使用索引EXPLAIN SELECT * FROM usersWHERE created_at >= '2026-01-01' AND created_at < '2027-01-01';-- type: range(范围扫描)-- key: idx_created_at
-- 示例2:索引失效EXPLAIN SELECT * FROM users WHERE username LIKE '%zhang%';-- type: ALL(索引失效)
-- 优化后:前缀匹配可以使用索引EXPLAIN SELECT * FROM users WHERE username LIKE 'zhang%';-- type: range-- key: uniq_username
-- 示例3:JOIN查询优化EXPLAIN SELECT u.*, o.*FROM users uLEFT JOIN orders o ON u.id = o.user_idWHERE u.status = 1;
-- 检查要点:-- 1. type是否为ALL(全表扫描)-- 2. key是否为NULL(未使用索引)-- 3. rows是否过大(扫描行数)-- 4. Extra是否包含Using filesort或Using temporaryEXPLAIN输出字段详解
| 字段 | 说明 | 关注要点 |
|---|---|---|
| id | 查询序列号 | 数字越大越先执行 |
| select_type | 查询类型 | SIMPLE/PRIMARY/SUBQUERY等 |
| table | 表名 | 访问哪个表 |
| type | 访问类型 | system>const>eq_ref>ref>range>index>ALL |
| possible_keys | 可能用到的索引 | 查询涉及的索引 |
| key | 实际用到的索引 | NULL表示未使用索引 |
| key_len | 索引长度 | 越短越好 |
| ref | 索引的哪一列被使用 | const/字段名 |
| rows | 扫描的行数 | 越少越好 |
| filtered | 过滤比例 | 越高越好 |
| Extra | 额外信息 | 重点关注 |
Extra字段重要值:
- Using index:使用覆盖索引(最优)
- Using where:使用WHERE过滤
- Using index condition:索引下推
- Using filesort:文件排序(需优化)
- Using temporary:使用临时表(需优化)
- Using join buffer:使用连接缓冲(需优化)
SQL优化实战案例
-- 问题SQL:慢查询SELECT * FROM usersWHERE status = 1 AND DATE(created_at) = '2026-05-19';
-- 问题分析:-- 1. DATE()函数导致索引失效-- 2. status字段基数低,索引效率不高
-- 优化方案1:去掉函数,使用范围查询SELECT * FROM usersWHERE status = 1 AND created_at >= '2026-05-19 00:00:00' AND created_at < '2026-05-20 00:00:00';
-- 优化方案2:创建联合索引ALTER TABLE users ADD INDEX idx_status_created (status, created_at);
-- 优化后的查询SELECT * FROM users USE INDEX (idx_status_created)WHERE status = 1 AND created_at >= '2026-05-19 00:00:00' AND created_at < '2026-05-20 00:00:00';-- 问题SQL:深分页性能差SELECT * FROM usersORDER BY created_at DESCLIMIT 1000000, 20;
-- 问题分析:需要扫描1000020行数据
-- 优化方案1:使用子查询SELECT * FROM usersWHERE id >= ( SELECT id FROM users ORDER BY created_at DESC LIMIT 1000000, 1)ORDER BY created_at DESCLIMIT 20;
-- 优化方案2:使用游标方式(记录上次查询的最后一条记录ID)SELECT * FROM usersWHERE id < 上次最后一条记录的IDORDER BY id DESCLIMIT 20;
-- 优化方案3:使用延迟关联SELECT a.* FROM users aJOIN ( SELECT id FROM users ORDER BY created_at DESC LIMIT 1000000, 20) b ON a.id = b.id;-- 问题SQL:多表JOIN性能差SELECT u.username, o.order_no, p.product_nameFROM users uLEFT JOIN orders o ON u.id = o.user_idLEFT JOIN order_items oi ON o.id = oi.order_idLEFT JOIN products p ON oi.product_id = p.idWHERE u.status = 1;
-- 优化方案:-- 1. 确保JOIN字段都有索引ALTER TABLE orders ADD INDEX idx_user_id (user_id);ALTER TABLE order_items ADD INDEX idx_order_id (order_id);ALTER TABLE order_items ADD INDEX idx_product_id (product_id);
-- 2. 先过滤再JOINSELECT u.username, o.order_no, p.product_nameFROM (SELECT * FROM users WHERE status = 1) uLEFT JOIN orders o ON u.id = o.user_idLEFT JOIN order_items oi ON o.id = oi.order_idLEFT JOIN products p ON oi.product_id = p.id;
-- 3. 使用STRAIGHT_JOIN强制JOIN顺序SELECT STRAIGHT_JOIN u.username, o.order_no, p.product_nameFROM users uJOIN orders o ON u.id = o.user_idJOIN order_items oi ON o.id = oi.order_idJOIN products p ON oi.product_id = p.idWHERE u.status = 1;3.2 索引设计与优化
索引是数据库性能优化的核心,合理的索引可以将查询速度提升几个数量级。
索引类型与选择
-- 1. 普通索引CREATE INDEX idx_username ON users(username);ALTER TABLE users ADD INDEX idx_email (email);
-- 2. 唯一索引CREATE UNIQUE INDEX uniq_email ON users(email);ALTER TABLE users ADD UNIQUE INDEX uniq_username (username);
-- 3. 主键索引ALTER TABLE users ADD PRIMARY KEY (id);
-- 4. 全文索引(用于文本搜索)CREATE FULLTEXT INDEX ft_content ON articles(content);ALTER TABLE articles ADD FULLTEXT INDEX ft_title_content (title, content);
-- 5. 联合索引(最左前缀原则)CREATE INDEX idx_status_created ON users(status, created_at);
-- 6. 空间索引(用于地理位置数据)CREATE SPATIAL INDEX idx_location ON stores(location);
-- 7. 前缀索引(节省空间)CREATE INDEX idx_email_prefix ON users(email(20));
-- 8. 降序索引(MySQL 8.0+)CREATE INDEX idx_created_desc ON users(created_at DESC);索引设计原则
索引设计黄金法则
- 选择性原则:索引列的值区分度越高,索引效果越好
- 最左前缀原则:联合索引遵循最左匹配原则
- 覆盖索引原则:尽量使用覆盖索引,避免回表
- 适度原则:不是索引越多越好,过多索引影响写入性能
- 监控原则:定期检查和清理无用索引
-- 计算字段的选择性(值越接近1越好)SELECT COUNT(DISTINCT status) / COUNT(*) AS status_selectivity, COUNT(DISTINCT email) / COUNT(*) AS email_selectivity, COUNT(DISTINCT username) / COUNT(*) AS username_selectivityFROM users;
-- 对于低选择性字段(如性别、状态),不适合单独建索引-- 可以考虑与其他字段组成联合索引
-- 示例:status字段选择性很低(只有0和1),但与created_at组成联合索引效果好ALTER TABLE users ADD INDEX idx_status_created (status, created_at);联合索引优化
-- 创建联合索引CREATE INDEX idx_abc ON table(a, b, c);
-- 以下查询可以使用该索引:SELECT * FROM table WHERE a = 1; -- 使用aSELECT * FROM table WHERE a = 1 AND b = 2; -- 使用a,bSELECT * FROM table WHERE a = 1 AND b = 2 AND c = 3;-- 使用a,b,cSELECT * FROM table WHERE a = 1 AND c = 3; -- 使用a(c用不上)
-- 以下查询不能使用该索引:SELECT * FROM table WHERE b = 2; -- 不符合最左原则SELECT * FROM table WHERE c = 3; -- 不符合最左原则SELECT * FROM table WHERE b = 2 AND c = 3; -- 不符合最左原则
-- 实战案例:用户查询索引设计-- 查询条件:status、created_at、last_login_at-- 最优索引顺序:WHERE条件中常量 > 范围 > 排序
-- 方案1:status是常量,created_at是范围CREATE INDEX idx_status_created ON users(status, created_at);
-- 方案2:如果经常按last_login_at排序CREATE INDEX idx_status_login_created ON users(status, last_login_at, created_at);覆盖索引优化
-- 问题查询:需要回表SELECT id, username, email FROM users WHERE status = 1;-- 如果只有 INDEX idx_status (status),需要:-- 1. 通过idx_status找到所有status=1的id-- 2. 通过id回表查询username和email
-- 优化:创建覆盖索引(包含所有需要的列)CREATE INDEX idx_status_username_email ON users(status, username, email);
-- 优化后查询(Using index,无需回表)EXPLAIN SELECT username, email FROM users WHERE status = 1;-- Extra: Using index
-- 实战案例:订单查询优化-- 原始查询SELECT order_no, user_id, amount, statusFROM ordersWHERE user_id = 12345 AND status = 'paid';
-- 创建覆盖索引CREATE INDEX idx_user_status_order_amountON orders(user_id, status, order_no, amount);
-- 优化效果:-- Before: type=ref, Extra=Using where-- After: type=ref, Extra=Using where; Using index索引维护
-- 1. 查看表的所有索引SHOW INDEX FROM users;
-- 2. 查看索引使用统计SELECT object_schema AS db, object_name AS table_name, index_name, count_star AS index_usage_count, sum_timer_wait / 1000000000000 AS total_time_secFROM performance_schema.table_io_waits_summary_by_index_usageWHERE object_schema = 'myapp' AND object_name = 'users'ORDER BY count_star DESC;
-- 3. 找出未使用的索引SELECT object_schema AS db, object_name AS table_name, index_nameFROM performance_schema.table_io_waits_summary_by_index_usageWHERE index_name IS NOT NULL AND count_star = 0 AND object_schema NOT IN ('mysql', 'performance_schema', 'sys')ORDER BY object_schema, object_name;
-- 4. 删除无用索引ALTER TABLE users DROP INDEX idx_unused;
-- 5. 重建索引(优化碎片)ALTER TABLE users DROP INDEX idx_username, ADD INDEX idx_username (username);
-- 或者使用OPTIMIZE TABLEOPTIMIZE TABLE users;
-- 6. 在线DDL(MySQL 5.6+,不锁表)ALTER TABLE usersADD INDEX idx_new_column (new_column),ALGORITHM=INPLACE, LOCK=NONE;3.3 主从复制架构深入
主从复制是MySQL高可用架构的基础,它可以实现数据备份、读写分离和故障切换。
主从复制原理
主从复制基于**二进制日志(binlog)**实现,主要包括三个线程:
- 主库Binlog Dump线程:读取binlog并发送给从库
- 从库I/O线程:接收binlog并写入relay log
- 从库SQL线程:读取relay log并执行SQL
主库 (Master) │ ├─> 执行SQL语句 ├─> 写入binlog ├─> Binlog Dump线程读取binlog └─> 发送给从库 │ ▼从库 (Slave) │ ├─> I/O线程接收binlog ├─> 写入relay log ├─> SQL线程读取relay log └─> 执行SQL语句主从复制完整配置
[mysqld]server-id = 1 # 服务器ID,主从环境中必须唯一
# binlog配置log_bin = /data/mysql/logs/mysql-bin # binlog文件路径binlog_format = ROW # binlog格式:ROW/STATEMENT/MIXEDmax_binlog_size = 1G # 单个binlog文件最大大小binlog_expire_logs_seconds = 604800 # binlog保留时间(7天)
# GTID配置(推荐)gtid_mode = ON # 启用GTIDenforce_gtid_consistency = ON # 强制GTID一致性log_slave_updates = ON # 从库是否记录复制的binlog
# 其他配置sync_binlog = 1 # binlog同步频率(1最安全)binlog_cache_size = 4M # binlog缓存大小max_binlog_cache_size = 512M # binlog缓存最大值
# 半同步复制(可选,提高数据安全性)plugin_load = "rpl_semi_sync_master=semisync_master.so"rpl_semi_sync_master_enabled = ONrpl_semi_sync_master_timeout = 1000 # 超时时间(毫秒)[mysqld]server-id = 2 # 从库ID,必须与主库不同
# relay log配置relay_log = /data/mysql/logs/mysql-relay-binrelay_log_index = /data/mysql/logs/mysql-relay-bin.indexrelay_log_recovery = ON # 崩溃恢复时自动修复relay log
# 只读配置(防止从库写入)read_only = ON # 普通用户只读super_read_only = ON # 超级用户也只读(MySQL 5.7+)
# GTID配置gtid_mode = ONenforce_gtid_consistency = ONlog_slave_updates = ON
# 从库并行复制(提高复制性能)slave_parallel_workers = 4 # 并行复制线程数slave_parallel_type = LOGICAL_CLOCK # 并行复制类型
# 半同步复制(可选)plugin_load = "rpl_semi_sync_slave=semisync_slave.so"rpl_semi_sync_slave_enabled = ON-- 1. 创建复制用户CREATE USER 'repl'@'192.168.1.%'IDENTIFIED WITH mysql_native_password BY 'Repl@2026!Strong';
-- 2. 授予复制权限GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'192.168.1.%';FLUSH PRIVILEGES;
-- 3. 查看主库状态(记录File和Position)SHOW MASTER STATUS\G-- *************************** 1. row ***************************-- File: mysql-bin.000001-- Position: 154-- Binlog_Do_DB:-- Binlog_Ignore_DB:-- Executed_Gtid_Set:
-- 4. 备份主库数据(用于初始化从库)-- 方法1:使用mysqldumpmysqldump -uroot -p --single-transaction --master-data=2 \ --all-databases > full_backup.sql
-- 方法2:使用xtrabackupxtrabackup --user=root --password=xxx --backup --target-dir=/backup/full-- 1. 停止从库(如果之前配置过)STOP SLAVE;
-- 2. 配置主库信息(使用GTID)CHANGE MASTER TO MASTER_HOST='192.168.1.100', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='Repl@2026!Strong', MASTER_AUTO_POSITION=1; -- 使用GTID自动定位
-- 如果不使用GTID,需要指定binlog位置CHANGE MASTER TO MASTER_HOST='192.168.1.100', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='Repl@2026!Strong', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154;
-- 3. 启动从库复制START SLAVE;
-- 4. 查看从库状态SHOW SLAVE STATUS\G
-- 重点检查以下字段:-- Slave_IO_Running: Yes # I/O线程运行状态-- Slave_SQL_Running: Yes # SQL线程运行状态-- Seconds_Behind_Master: 0 # 主从延迟(秒)-- Last_IO_Error: # I/O错误信息-- Last_SQL_Error: # SQL错误信息-- Executed_Gtid_Set: # 已执行的GTID集合主从复制故障处理
-- ============ 问题1:主从延迟过大 ============
-- 1. 查看延迟情况SHOW SLAVE STATUS\G-- Seconds_Behind_Master: 300 # 延迟300秒
-- 2. 分析原因-- a) 查看从库是否有慢查询SHOW FULL PROCESSLIST;
-- b) 查看从库负载-- CPU、内存、磁盘IO是否过高
-- c) 查看是否启用并行复制SHOW VARIABLES LIKE 'slave_parallel%';
-- 3. 解决方案-- 方案1:启用并行复制STOP SLAVE;SET GLOBAL slave_parallel_workers = 4;SET GLOBAL slave_parallel_type = LOGICAL_CLOCK;START SLAVE;
-- 方案2:升级从库硬件-- 方案3:优化慢查询-- 方案4:读写分离,减少从库查询压力
-- ============ 问题2:主从同步中断 ============
-- 1. 查看错误信息SHOW SLAVE STATUS\G-- Slave_IO_Running: No-- Last_IO_Error: error connecting to master 'repl@192.168.1.100:3306'
-- 2. 解决方案:网络问题-- 检查网络连接ping 192.168.1.100telnet 192.168.1.100 3306
-- 重启I/O线程STOP SLAVE IO_THREAD;START SLAVE IO_THREAD;
-- 3. SQL线程错误(数据冲突)SHOW SLAVE STATUS\G-- Slave_SQL_Running: No-- Last_SQL_Error: Duplicate entry '123' for key 'PRIMARY'
-- 方案1:跳过错误事务(谨慎使用,可能导致数据不一致)STOP SLAVE;SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;START SLAVE;
-- 方案2:使用GTID跳过错误事务STOP SLAVE;SET GTID_NEXT='错误事务的GTID'; -- 从Last_SQL_Error中获取BEGIN; COMMIT;SET GTID_NEXT='AUTOMATIC';START SLAVE;
-- 方案3:手动修复数据后重启-- 例如:删除重复数据DELETE FROM users WHERE id = 123;START SLAVE;
-- ============ 问题3:主从数据不一致 ============
-- 使用pt-table-checksum检查数据一致性pt-table-checksum --host=主库IP \ --user=checksum_user \ --password=password \ --databases=myapp \ --replicate=percona.checksums
-- 使用pt-table-sync修复数据不一致pt-table-sync --execute \ --sync-to-master \ --user=sync_user \ --password=password \ 从库IP
-- ============ 问题4:主从切换 ============
-- 场景:主库故障,需要提升从库为主库
-- 1. 在从库上停止复制STOP SLAVE;RESET SLAVE ALL;
-- 2. 在从库上禁用只读SET GLOBAL read_only = OFF;SET GLOBAL super_read_only = OFF;
-- 3. 配置新的从库指向新的主库-- 在其他从库上执行:STOP SLAVE;CHANGE MASTER TO MASTER_HOST='新主库IP', MASTER_AUTO_POSITION=1;START SLAVE;3.4 分库分表基础
当单表数据量达到千万级以上时,查询性能会明显下降,这时就需要考虑分库分表。
分库分表方式
垂直拆分:├─ 垂直分库:按业务模块拆分到不同数据库│ └─ 例:用户库、订单库、商品库└─ 垂直分表:按字段拆分到不同表 └─ 例:用户基础表、用户扩展表
水平拆分:├─ 水平分库:同一类数据分散到多个数据库│ └─ 例:user_db_0, user_db_1, user_db_2└─ 水平分表:同一类数据分散到多个表 └─ 例:user_0, user_1, user_2常见分片算法
-- ============ 1. 范围分片 ============-- 按用户ID范围分片(简单但容易数据倾斜)
-- 分片规则:-- user_0: id 1-1000000-- user_1: id 1000001-2000000-- user_2: id 2000001-3000000
-- 路由算法(应用层实现)table_suffix = (user_id - 1) / 1000000table_name = 'user_' + table_suffix
-- ============ 2. 哈希分片 ============-- 按用户ID哈希值分片(数据分布均匀)
-- 分片规则:4个分片-- 路由算法table_suffix = user_id % 4table_name = 'user_' + table_suffix
-- ============ 3. 一致性哈希 ============-- 解决哈希分片的扩容问题-- 使用虚拟节点技术
-- ============ 4. 时间分片 ============-- 按时间范围分片(适合日志、订单等场景)
-- 分片规则:按月分表-- order_202601, order_202602, order_202603
-- 路由算法table_name = 'order_' + DATE_FORMAT(order_time, '%Y%m')
-- ============ 5. 地理位置分片 ============-- 按地区分片
-- 分片规则:-- user_cn_north: 华北用户-- user_cn_south: 华南用户-- user_cn_east: 华东用户分库分表中间件
主流分库分表中间件
ShardingSphere:Apache开源项目,功能强大
Waiting for api.github.com...MyCat:国产开源,简单易用
Vitess:YouTube开源,适合大规模场景
Waiting for api.github.com...TDDL:阿里巴巴开源
云厂商方案:阿里云PolarDB-X、腾讯云TDSQL等
分库分表注意事项
分库分表的挑战
- 跨分片JOIN:需要应用层聚合或使用宽表冗余
- 分布式事务:使用两阶段提交或最终一致性
- 全局唯一ID:使用雪花算法或分布式ID生成器
- 数据迁移:扩容时需要迁移数据,停机时间长
- 运维复杂度:多个数据库实例增加运维难度
-- 1. 设计合理的分片键-- 选择经常出现在WHERE条件中的字段-- 避免使用经常变化的字段
-- 2. 避免跨分片查询-- 不推荐:SELECT * FROM user WHERE email = 'xxx@example.com';-- 问题:email不是分片键,需要查询所有分片
-- 推荐:SELECT * FROM user WHERE user_id = 12345;-- user_id是分片键,可以精确定位到某个分片
-- 3. 使用全局唯一ID-- 雪花算法(Snowflake)生成64位ID-- 结构:1位符号位 + 41位时间戳 + 10位机器ID + 12位序列号
-- 4. 冗余数据解决跨分片JOIN-- 订单表冗余用户信息CREATE TABLE order ( id BIGINT PRIMARY KEY, user_id BIGINT, user_name VARCHAR(50), -- 冗余 user_mobile VARCHAR(20), -- 冗余 order_no VARCHAR(50), amount DECIMAL(10,2));四、总结与学习路径
MySQL是一个非常庞大和复杂的系统,想要完全掌握它需要长期的学习和实践。作为一名系统运维人员,你不需要成为MySQL开发专家,但你必须掌握本文提到的所有核心技能,这样才能在生产环境中从容应对各种问题。
运维人员MySQL技能检查清单
## 基础技能(必须掌握)- [ ] 能够独立安装部署MySQL(多种方式)- [ ] 熟练配置my.cnf核心参数- [ ] 掌握用户权限管理- [ ] 掌握数据库、表、数据的基本操作- [ ] 能够进行数据备份与恢复- [ ] 掌握慢查询日志分析
## 进阶技能(重点掌握)- [ ] 理解InnoDB存储引擎原理- [ ] 掌握EXPLAIN执行计划分析- [ ] 能够设计和优化索引- [ ] 掌握主从复制配置与故障处理- [ ] 掌握常用性能监控指标- [ ] 能够进行基础SQL优化
## 高级技能(逐步学习)- [ ] 理解MySQL锁机制和事务原理- [ ] 掌握binlog和GTID- [ ] 能够搭建高可用架构(MHA/MGR)- [ ] 掌握MySQL性能调优方法论- [ ] 了解分库分表原理和方案- [ ] 能够处理复杂的数据库故障
## 专家技能(深入研究)- [ ] 理解MySQL内核架构- [ ] 能够进行深度性能调优- [ ] 掌握MySQL源码阅读- [ ] 能够设计大规模数据库架构- [ ] 掌握数据库中间件使用学习路径建议
阶段1:基础入门(1-3个月)
- 学习MySQL安装部署
- 掌握SQL基本语法
- 理解数据库、表、索引概念
- 学习用户权限管理
- 实践备份恢复操作
阶段2:运维进阶(3-6个月)
- 深入学习InnoDB原理
- 掌握慢查询分析与SQL优化
- 学习主从复制配置
- 实践性能监控与调优
- 学习高可用架构方案
阶段3:高级运维(6-12个月)
- 深入研究MySQL内核
- 学习分库分表方案
- 掌握大规模集群运维
- 学习容器化部署(K8s)
- 研究云原生数据库
阶段4:专家级(1年以上)
- 阅读MySQL源码
- 参与开源社区贡献
- 设计企业级数据库架构
- 输出技术分享和文章
推荐学习资源
书籍推荐:
- 《高性能MySQL》(第4版)- MySQL优化圣经
- 《MySQL技术内幕:InnoDB存储引擎》- 深入理解InnoDB
- 《MySQL运维内参》- 运维实战经验
- 《数据库系统概念》- 数据库理论基础
在线资源:
- MySQL官方文档:https://dev.mysql.com/doc/
- Percona博客:https://www.percona.com/blog/
- MySQL Performance Blog:https://www.percona.com/blog/
- Planet MySQL:https://planet.mysql.com/
- 极客时间《MySQL实战45讲》
实用工具:
持续学习建议
成长建议
- 动手实践:搭建本地MySQL环境,模拟各种故障场景
- 阅读源码:从简单模块开始,逐步深入MySQL内核
- 参与社区:在Stack Overflow、GitHub上回答问题和贡献代码
- 写技术博客:记录学习过程和踩坑经验
- 定期总结:每月总结工作中遇到的问题和解决方案
- 关注新技术:跟进MySQL新版本特性和云原生数据库发展
最后的话
作为MySQL运维人员,请牢记以下原则:
- 安全第一:任何操作前先备份,生产环境操作需二次确认
- 监控为王:完善的监控系统是发现问题的第一步
- 自动化运维:重复性工作尽量脚本化、自动化
- 文档先行:所有架构和操作都要有详细文档
- 持续学习:技术日新月异,保持学习热情
最后,我想强调的是,实践是最好的老师。只有在实际工作中不断遇到问题、解决问题,你才能真正掌握MySQL运维技能。同时,要养成良好的运维习惯,比如操作前备份、变更前测试、定期巡检等,这些习惯可以帮助你避免很多不必要的故障。
祝你在MySQL运维的道路上越走越远,成为一名优秀的数据库专家!🚀
相关文章推荐: