MySQL 故障排查与生产环境优化

目录

一、前置知识点

MySQL的运行原理

[1. 客户端连接](#1. 客户端连接)

[2. SQL 解析与优化](#2. SQL 解析与优化)

[3. 存储引擎处理](#3. 存储引擎处理)

[4. 日志与持久化](#4. 日志与持久化)

[二、MySQL 单实例故障排查](#二、MySQL 单实例故障排查)

(1)故障现象1

(2)故障现象2

(3)故障现象3

(4)故障现象4

(5)故障现象5

(6)故障现象6

(7)故障现象7

(8)故障现象8

[三、MySQL 主从故障排查](#三、MySQL 主从故障排查)

(1)故障现象1

(2)故障现象2

(3)故障现象3

[四、MySQL 优化](#四、MySQL 优化)

1、硬件方面

[(1)关于 CPU](#(1)关于 CPU)

(2)关于内存

(3)关于磁盘

[2、MySQL 配置文件](#2、MySQL 配置文件)

(1)核心功能优化项

(2)查询优化项

(3)日志与监控

[(4)InnoDB 高级优化](#(4)InnoDB 高级优化)

(5)示例配置(my.cnf)

[3、SQL 方面](#3、SQL 方面)

(1)创建测试表并插入数据

[(2)使用 EXPLAIN 进行 SQL 优化的步骤及实验验证](#(2)使用 EXPLAIN 进行 SQL 优化的步骤及实验验证)

(3)优化步骤:添加索引

[(4)优化后查询及 EXPLAIN 分析](#(4)优化后查询及 EXPLAIN 分析)


一、前置知识点

MySQL的运行原理

1. 客户端连接
  • 客户端通过 TCP/IP 或 Socket 连接到 MySQL 服务端。

  • 连接管理器(Connection Manager)负责管理线程池和用户认证。

2. SQL 解析与优化
  • 解析器:将 SQL 语句解析为语法树,验证语法合法性。

  • 优化器:生成执行计划,选择索引或全表扫描等策略。

3. 存储引擎处理
  • 执行引擎:调用存储引擎(如 InnoDB、MyISAM)执行读写操作。

  • 数据存储

    • InnoDB:数据存储在表空间文件(.ibd)中,支持事务和行级锁。

    • MyISAM:数据存储在 .MYD(数据文件)和 .MYI(索引文件)中,不支持事务。

4. 日志与持久化
  • Redo Log(重做日志):确保事务的持久性,崩溃恢复时重放未提交的事务。

  • Undo Log(回滚日志):支持事务回滚和多版本并发控制(MVCC)。

  • Binlog(二进制日志):记录所有数据变更,用于主从复制和增量备份。

二、MySQL 单实例故障排查

(1)故障现象1

复制代码
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/data/mysql/mysql.sock' (2)

问题分析 :以上这种情况一般都是数据库未启动、mysql 配置文件未指定 socket 文件或者数据库端口被防火墙拦截导致。
解决方法:启动数据库或者防火墙开放数据库监听端口。

(2)故障现象2

复制代码
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

问题分析 :密码不正确或者没有权限访问。
解决方法

修改 my.cnf 主配置文件,在 [mysqld] 下添加 skip - grant - tables=on,重启数据库。最后修改密码命令如下:

Mysql5.7 版本

复制代码
mysql> update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
mysql> flush privileges;

Mysql8.0

复制代码
mysql> UPDATE mysql.user SET authentication_string='' WHERE user='root' AND Host='localhost';
mysql> FLUSH PRIVILEGES;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';

再删除刚刚添加的 skip-grant-tables 参数,重启数据库,使用新密码即可登录。重新授权,命令如下。

Mysql5.7

复制代码
mysql>grant all on *.* to 'root'@'mysql-server' identified by '123456';

Mysql8.0

复制代码
mysql> CREATE USER 'root'@'mysql-server' IDENTIFIED BY '123456';
mysql> GRANT all ON *.* TO 'root'@'mysql-server';

(3)故障现象3

复制代码
使用远程连接数据库时偶尔会发生远程连接数据库很慢的问题

问题分析:如果MySQL主机查询DNS很慢或有很多客户端连接导致很慢,由于开发机器是不可以连接外网的,在进行MySQL连接时,DNS解析是不可能完成的,从而也就明白了连接那么慢的原因。

解决方法:修改配置文件my.cnf ,在[mysql] 下添加 skip-name-resolve,重启数据库可以解决,注意在以后授权里面不能再使用主机名授权。

(4)故障现象4

复制代码
Can't open file: 'xxx_forums.MYI'. (errno: 145)

问题分析:服务器非正常关机,数据库所在空间已满,或一些其他未知原因,对数据库表造成了损坏。可能是系统下直接将数据库文件拷贝,会因为文件的属组问题产生这个错误。

解决方法

1.可以使用两种方式修复数据表

  • 使用 MySQL 自带的专门用户数据表检查和修复工具 myisamchk。一般情况下只有在命令行下面才能运行 myisamchk 命令。常用的修复命令为:

    myisamchk -r 数据文件目录/数据表名.MYI;

  • 通过 phpMyAdmin 修复,phpMyAdmin 带有修复数据表的功能,进入到某一个表中后,点击 "操作",在下方的 "表维护" 中点击 "修复表" 即可。

注意:以上两种修复方式在执行前一定要备份数据库。

  • 修改文件的属组(仅适合独立主机用户):
  • 复制数据库文件的过程中没有将数据库文件设置为 MySQL 运行的帐号可读写(一般适用于 Linux 和 FreeBSD 用户)。

(5)故障现象5

复制代码
ERROR 1129 (HY000): Host 'xxx.xxx.xxx' is blocked because of many connection erros;
unblock with 'mysqladmin flush-hosts'

问题分析:由于数据库参数:max_connect_errors , 其默认值是10.当大量的主机去连接MySQL ,总连接请求超过了,新的连接就无法连上MySQL。同一个IP在短时间内产生太多中断的数据库连接而导致的阻塞。

解决方法:使用 mysqladmin flush-hosts 命令清除缓存

(6)故障现象6

复制代码
客户端报 Too many connections.

问题分析:连接数超出MySQL的最大连接数限制

解决方法:1.在 /etc/my.cnf 配置文件增大连接数,然后重启MySQL

max_connections = 10000

2.临时修改最大连接数,在my.cnf 里修改

set GLOBL max_connections = 10000

(7)故障现象7

复制代码
Warning:World-writable config file '/etc/my.cnf' is ignored
ERROR! MySQL is running but PID file could not be found

问题分析:MySQL 的配置文件/etc/my.cnf 权限不对

解决方法:给它权限 chmod 644 /etc/my.cnf

(8)故障现象8

复制代码
InnoDB: Error:page 14178 log sequence number 29455369832
InnoDB:is in the future!Current system log sequence number 29455369832f

问题分析: innodb 数据文件损坏。

解决方法:修改 my.cnf 配置文件,在[mysql] 下添加 innodb_force_recovery=4,启动数据库后备份数据文件,然后去掉该参数,利用备份文件恢复数据。

三、MySQL 主从故障排查

(1)故障现象1

复制代码
从库的 Slave_IO_Running 为 NO
The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id option must be used on slave but this does not always make sense; please check the manual before using it).

问题分析 :主库和从库的 server-id 值一样。
解决方法:修改从库的 server-id 的值,修改为和主库不一样。修改完后重启,再同步即可。

(2)故障现象2

复制代码
从库的 Slave_IO_Running 为 NO

问题分析:造成从库线程为 NO 的原因会有很多,主要原因是主键冲突或者主库删除或更新数据,从库找不到记录,数据被修改导致。通常状态码报错有 1007、1032、1062、1452 等。

解决方法一

复制代码
mysql> stop slave;
mysql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
mysql> start slave;

解决方法二

设置用户权限,设置从库只读权限

复制代码
set global read_only=true;

(3)故障现象3

复制代码
Error initializing relay log position: I/O error reading the header from the binary log

分析问题:从库的中继日志 relay-bin 损坏。

解决方法:手工修复,重新找到同步的 binlog 和 pos 点,然后重新同步即可。

复制代码
mysql>CHANGE  MASTER  TO  MASTER_LOG_FILE='mysql-bin.xxx', MASTER_LOG_POS=xxx;

四、MySQL 优化

1、硬件方面

(1)关于 CPU

优化目标

  • 提升并行处理能力,减少 SQL 执行和锁竞争带来的 CPU 瓶颈。

关键策略

  1. 选择多核 CPU

    • MySQL 支持多线程操作(如并行查询、连接处理),多核 CPU 能更好地处理高并发请求。

    • 建议:优先选择主频高、核心数多的 CPU(如 16 核以上)。

  2. 监控 CPU 使用率

    复制代码
    # 查看 CPU 负载  
    top  
    # 检查用户态(us)和内核态(sy)的 CPU 占用  
    vmstat 1  
    • 常见问题

      • us 高:SQL 执行消耗过多 CPU(需优化慢查询)。

      • sy 高:系统内核资源争用(如锁竞争、线程切换)。

  3. 优化锁与并发

    • 减少表锁(MyISAM)或行锁(InnoDB)竞争:

      复制代码
      -- 查看锁等待  
      SHOW ENGINE INNODB STATUS\G  
      -- 查看当前运行事务  
      SELECT * FROM information_schema.INNODB_TRX;  
(2)关于内存

优化目标

  • 最大化利用内存缓存数据,减少磁盘 I/O。

关键策略

  1. 配置 InnoDB 缓冲池

    • innodb_buffer_pool_size 是 InnoDB 引擎的核心参数,用于缓存数据和索引。

    • 建议 :设置为系统总内存的 70%~80%(需预留内存给操作系统和其他进程)。

      复制代码
      # my.cnf 示例  
      innodb_buffer_pool_size = 64G  
  2. 优化其他内存区域

    • 连接线程内存

      复制代码
      thread_cache_size = 100      # 缓存线程数  
      max_connections = 1000       # 最大连接数  
    • 排序和临时表内存

      复制代码
      sort_buffer_size = 4M        # 排序缓冲区  
      tmp_table_size = 256M        # 内存临时表大小  
  3. 监控内存使用

    复制代码
    -- 查看 InnoDB 缓冲池命中率  
    SHOW STATUS LIKE 'Innodb_buffer_pool_read%';  
    -- 计算命中率公式:  
    -- (1 - Innodb_buffer_
(3)关于磁盘

优化目标

  • 提升 I/O 吞吐量,降低数据读写延迟。

关键策略

  1. 选择高性能存储设备

    • SSD:比 HDD 快 10 倍以上,尤其适合随机 I/O 密集场景。

    • RAID 配置

      • RAID 10:兼顾性能与冗余,适合 OLTP 场景。

      • RAID 5:适合读多写少的 OLAP 场景。

  2. 分离日志与数据文件

    • 日志文件(binlog、redo log):

      • 写入频繁且顺序写入,建议单独挂载高速 SSD。
    • 数据文件

      • 随机读写较多,使用独立磁盘或 RAID 10。
  3. 优化文件系统与 I/O 调度

    • 文件系统 :使用 XFS 或 ext4(启用 noatime 减少元数据写入)。

    • I/O 调度器

      复制代码
      # 查看当前调度策略  
      cat /sys/block/sda/queue/scheduler  
      # 设置为 deadline 或 noop(SSD 推荐)  
      echo 'deadline' > /sys/block/sda/queue/scheduler  
  4. 监控磁盘 I/O

    复制代码
    # 查看磁盘吞吐量和延迟  
    iostat -x 1  
    # 检查 I/O 等待时间  
    top(关注 %wa 指标)  

2、MySQL 配置文件

(1)核心功能优化项
参数 作用 建议配置 注意事项
innodb_buffer_pool_size InnoDB 缓冲池大小,缓存数据和索引,直接影响读性能 设置为物理内存的 50%~70%(如 64GB 内存配 40G) 避免超过物理内存,防止系统交换(Swap)
innodb_log_file_size 单个 InnoDB 重做日志文件大小,影响事务提交速度和崩溃恢复时间 建议 1G~4G(如 2G) 修改需停止 MySQL,删除旧日志文件后重启
innodb_flush_log_at_trx_commit 控制事务日志刷新策略,平衡性能与数据安全 1(默认,完全持久化);2(折中,每秒刷盘);0(高性能,风险高) 高并发写入场景可设为 2,但需容忍最多 1 秒数据丢失
max_connections 最大客户端连接数,避免连接耗尽 根据业务需求设置,建议 500~2000 监控 Threads_connected 和 Threads_running 调整
tmp_table_size、max_heap_table_size 内存临时表大小上限,影响复杂查询(如 GROUP BY、JOIN) 建议 64M~256M(如 128M),两者值需一致 过小会导致磁盘临时表,降低性能;过大可能耗尽内存
(2)查询优化项
参数 作用 建议配置
query_cache_type 查询缓存类型(MySQL 8.0 已移除,旧版本慎用) OFF(默认,高并发下建议关闭)
sort_buffer_size 排序操作缓冲区大小 2M~8M(如 4M)
join_buffer_size JOIN 操作缓冲区大小 4M~16M(如 8M,仅对无索引 JOIN 有效)
read_buffer_size 顺序读缓冲区大小 2M~8M(如 4M)
read_rnd_buffer_size 随机读缓冲区大小 4M~16M(如 8M)
(3)日志与监控
参数 作用 建议配置
slow_query_log 启用慢查询日志 ON
long_query_time 定义慢查询阈值(秒),记录执行时间长的 SQL 1~2(根据业务容忍度调整)
log_error 错误日志路径,用于故障排查 指定路径(如 /var/log/mysql/error.log )
binlog_format 二进制日志格式(主从复制依赖) ROW(推荐,数据一致性高)
expire_logs_days 自动清理旧的二进制日志天数 7~14(根据备份策略调整)
(4)InnoDB 高级优化
参数 作用 建议配置
innodb_io_capacity InnoDB 后台任务的 I/O 能力(如刷新脏页) SSD 建议 2000~4000,HDD 建议 200~400
innodb_flush_method 控制数据文件与日志文件的刷新方式 O_DIRECT(默认,避免双缓冲)
innodb_thread_concurrency InnoDB 并发线程数(默认,自适应),高并发场景影响性能 可设为 CPU 核数 * 2
innodb_autoinc_lock_mode 自增锁模式,影响插入(连续模式,高并发插入性能) 2
(5)示例配置(my.cnf)

物理资源 32 核 CPU、64G 内存、500G SSD

bash 复制代码
[mysqld]
# 核心配置
innodb_buffer_pool_size = 40G
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 2
max_connections = 1000
thread_cache_size = 100
# 查询优化
tmp_table_size = 128M
max_heap_table_size = 128M
sort_buffer_size = 4M
join_buffer_size = 8M
# 日志与监控
slow_query_log = ON
long_query_time = 1
log_error = /var/log/mysql/error.log
binlog_format = ROW
expire_logs_days = 7
# InnoDB 高级
innodb_io_capacity = 2000
innodb_flush_method = O_DIRECT
innodb_thread_concurrency = 0
innodb_autoinc_lock_mode = 2

3、SQL 方面

SQL 优化是保障数据库高效运行的关键,核心是减少 CPU、内存、磁盘 I/O 等资源消耗,提升查询响应。未优化 SQL 在大数据量或高并发时会引发全表扫描等问题,致服务器负载高、响应慢,影响业务。可借助索引优化等手段降低数据库压力,支持业务扩展,控制成本与运维复杂度。

(1)创建测试表并插入数据
bash 复制代码
-- 创建数据库
Create database test;
-- 使用数据库
Use test;

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL,
    age INT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

--插入 10 万条测试数据(使用存储过程生成)
DELIMITER $$
CREATE PROCEDURE insert_users()
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < 100000 DO
        INSERT INTO users (name, email, age)
        VALUES (CONCAT('user', i), CONCAT('user', i, '@example.com'), FLOOR(RAND() * 100));
        SET i = i + 1;
    END WHILE;
END$$
DELIMITER ;

CALL insert_users();
(2)使用 EXPLAIN 进行 SQL 优化的步骤及实验验证

EXPLAIN 是 MySQL 分析 SQL 执行计划的工具,模拟查询执行输出访问类型、索引使用、扫描行数、额外操作等关键信息,能帮开发者找出全表扫描、索引失效等性能问题,进而从添加索引、改写查询、调整表结构等方面优化,是提升数据库效率的重要诊断工具。

例如:

复制代码
mysql>EXPLAIN SELECT * FROM users WHERE name = 'user123';

EXPLAIN 用于显示 MySQL 如何执行一条 SQL 语句,关键字段如下:

字段 说明 优化关注点
id 查询序列号,相同 id 为同一执行层,不同 id 按序执行(如查看复杂查询的嵌套层级) -
select_type 查询类型(SIMPLE、PRIMARY、SUBQUERY、DERIVED 等) 识别子查询或临时表操作
table 访问的表名或别名 确认查询涉及的表
type 访问类型,性能从优到劣:system > const > eq_ref > ref > range > index > ALL 避免 ALL(全表扫描),优先优化为 ref 或 range
possible_keys 可能使用的索引 检查是否有合适索引未被使用
key 实际使用的索引 确认是否命中最佳索引
rows 预估扫描的行数 行数越少,查询效率越高
Extra 附加信息(如 Using where、Using index、Using temporary 等) 发现潜在性能问题(

根据关键字段说明,对 explain SELECT * FROM users WHERE name = 'user123' 的结果分析如下:

  • type=ALL:全表扫描,效率极低。
  • possible_keys=NULL:未命中索引。
  • rows=100000:扫描全部数据。
(3)优化步骤:添加索引
bash 复制代码
mysql>ALTER TABLE users ADD INDEX idx_name (name);
(4)优化后查询及 EXPLAIN 分析
bash 复制代码
mysql>EXPLAIN SELECT * FROM users WHERE name = 'user123';

优化后结果分析如下:

  • type=ref:索引查找,效率高。
  • key=idx_name:命中新创建的索引。
  • rows=1:仅扫描一行数据。
相关推荐
不穿铠甲的穿山甲3 分钟前
mysql-Java手写分布式事物提交流程
java·分布式·mysql
mxs052325 分钟前
抢购Python代码示例与技术解析
开发语言·数据库·python
Hadoop_Liang27 分钟前
openEuler24.03 LTS下安装MySQL8.0.42
数据库·mysql·openeuler
LB21121 小时前
黑马 javaweb Day07 MySQL --DQL(查询)语句
android·数据库·mysql
掘根1 小时前
【MySQL】使用文件进行交互
数据库·mysql
昭阳~1 小时前
MySQL故障排查与生产环境优化
数据库·mysql·oracle
猴子请来的逗比4892 小时前
mysql的安装方式
linux·数据库·学习·mysql
白初&2 小时前
CVE-2015-3934 Fiyo CMS SQL注入
数据库·sql
IT邦德2 小时前
MySQL企业版免费开启,强先体验
数据库·mysql
艺杯羹3 小时前
数据库连接池技术与 Druid 连接工具类实现
java·数据库·mysql·jdbc