MySQL故障排查与优化

一、故障排查核心原则与准备工作

1.1 核心原则

先恢复服务,再定位根因;先排查硬件/环境,再排查软件/配置;先排查全局问题,再排查局部问题(如单表、单SQL)。

排查过程中做好记录(故障现象、操作步骤、执行结果),避免误操作扩大故障范围,严禁在生产环境随意执行高危命令(如drop、alter等)。

1.2 准备工作

  • 工具准备:MySQL客户端(mysql、navicat)、监控工具(Prometheus+Grafana、Zabbix)、日志查看工具(tail、less、grep)、性能分析工具(explain、show profile、pt-query-digest)。

  • 权限准备:确保拥有MySQL的super、process、select权限,可查看日志、进程、表结构等。

  • 环境信息收集:MySQL版本、操作系统版本、服务器配置(CPU、内存、磁盘)、数据库架构(主从、集群)、当前业务量。

二、常见故障排查(按故障类型分类)

2.1 连接类故障(无法连接MySQL)

2.1.1 故障现象

客户端报错:"Can't connect to MySQL server on 'xxx' (111)"(连接拒绝)、"Lost connection to MySQL server at 'reading initial communication packet'"(连接中断)、"Access denied for user 'xxx'@'xxx' (using password: YES)"(权限拒绝)。

2.1.2 排查步骤

  1. 检查MySQL服务状态:systemctl status mysqld(Linux)、net start mysql(Windows),确认服务是否启动。若未启动,查看启动日志(/var/log/mysqld.log)排查启动失败原因(如配置文件错误、端口占用、数据目录权限不足)。

  2. 检查网络连通性:ping 数据库IP(检查网络可达)、telnet 数据库IP 端口(默认3306,检查端口是否开放)。若端口不通,排查防火墙(iptables、firewalld)是否拦截,或端口被其他进程占用(netstat -tulnp | grep 3306)。

  3. 检查MySQL配置:查看my.cnf(Linux)/my.ini(Windows)中的bind-address(是否限制了连接IP)、port(是否修改了默认端口)、max_connections(是否达到最大连接数)。

  4. 检查用户权限:登录MySQL(本地登录,如mysql -u root -p),执行select user,host,password_expired from mysql.user where user='xxx';,确认用户是否存在、host是否允许当前客户端IP、密码是否过期、是否有连接权限(grant all on *.* to 'xxx'@'xxx' identified by 'xxx'; 授权)。

2.2 查询缓慢故障(SQL执行卡顿)

2.2.1 故障现象

单条SQL执行时间过长(超过1s)、批量查询卡顿、应用接口超时,数据库CPU、IO使用率异常偏高。

2.2.2 排查步骤

  1. 定位慢SQL:开启慢查询日志(临时开启:set global slow_query_log=1;set global long_query_time=1;(超过1s记录)),查看慢查询日志(默认/var/log/mysqld-slow.log),或使用show processlist;查看当前运行的进程,找到状态为"Query"且时间过长的SQL。

  2. 分析慢SQL:使用explain分析SQL执行计划,重点关注:

    1. type:连接类型,优先级从高到低为system > const > eq_ref > ref > range > index > all(all为全表扫描,性能最差)。

    2. key:是否使用了索引(NULL表示未使用索引)。

    3. rows:预计扫描的行数,行数越多,性能越差。

    4. Extra:是否有"Using filesort"(文件排序,需优化)、"Using temporary"(临时表,需优化)。

  3. 排查索引问题:查看表结构(show create table 表名;),确认是否创建了合适的索引(主键索引、唯一索引、联合索引),索引是否失效(如使用函数、模糊查询%开头、类型不匹配、联合索引顺序错误)。

  4. 排查表数据量:查看表行数(select count(*) from 表名;),若数据量过大(百万级以上),需考虑分表、分区,或优化查询条件。

2.3 数据库卡死/宕机故障

2.3.1 故障现象

MySQL服务无响应、客户端无法连接、服务器CPU/内存/IO使用率达到100%,甚至服务器重启。

2.3.2 排查步骤

  1. 紧急恢复:若服务宕机,先重启MySQL服务(systemctl restart mysqld),恢复业务后再排查根因;若服务卡死,先执行show processlist;,杀死阻塞进程(kill 进程ID;),优先杀死长时间运行、无意义的查询进程。

  2. 查看系统日志:Linux查看/var/log/messages(系统日志)、/var/log/mysqld.log(MySQL错误日志),Windows查看事件查看器,排查是否有硬件故障(CPU、内存、磁盘损坏)、系统资源耗尽(内存溢出、磁盘满)。

  3. 排查磁盘空间:df -h(Linux)查看磁盘使用率,若磁盘满(超过90%),删除无用日志、临时文件,或扩展磁盘空间;MySQL数据目录(如/var/lib/mysql)满会导致服务卡死,需清理二进制日志(purge binary logs before '2026-04-01 00:00:00';)。

  4. 排查死锁:执行show engine innodb status;查看死锁信息,找到死锁的SQL和事务,优化SQL逻辑,避免事务长时间占用资源,或调整事务隔离级别。

  5. 排查配置问题:查看my.cnf中的内存配置(innodb_buffer_pool_sizesort_buffer_sizejoin_buffer_size),若内存配置过高,导致系统内存不足,触发OOM(Out Of Memory),会导致MySQL宕机,需合理调整配置(如innodb_buffer_pool_size建议设置为服务器内存的50%-70%)。

2.4 数据异常故障(丢失、错乱)

2.4.1 故障现象

数据查询不到、数据重复、数据被误删/修改、主从数据不一致。

2.4.2 排查步骤

  1. 排查操作记录:查看MySQL二进制日志(binary log),执行show binary logs;,找到对应时间的日志文件,使用mysqlbinlog 日志文件 --start-datetime='xxx' --stop-datetime='xxx'查看操作记录,确认是否有误操作(如delete、update未加条件)。

  2. 数据恢复:若数据丢失,可通过二进制日志恢复(基于时间点恢复)、备份文件恢复(若有全量备份+增量备份);若主从数据不一致,先停止从库同步(stop slave;),重新执行全量备份同步,再开启同步(start slave;),查看同步状态(show slave status\G;),确保Slave_IO_Running和Slave_SQL_Running均为Yes。

  3. 排查事务问题:查看是否有未提交的事务(select * from information_schema.innodb_trx;),未提交的事务会导致数据不可见,需提交(commit;)或回滚(rollback;)。

三、MySQL优化(分维度优化)

3.1 配置优化(my.cnf核心配置)

核心配置优化(基于Linux系统,根据服务器配置调整),重点关注以下参数:

  • 内存配置:

    • innodb_buffer_pool_size:InnoDB缓冲池大小,建议设置为服务器内存的50%-70%,用于缓存表数据和索引,减少磁盘IO。

    • sort_buffer_size:排序缓冲区大小,每个连接独立分配,建议设置为1-4M,避免过大导致内存耗尽。

    • join_buffer_size:连接缓冲区大小,每个连接独立分配,建议设置为1-4M,优化多表连接性能。

  • 日志配置:

    • slow_query_log=1:开启慢查询日志,便于定位慢SQL。

    • long_query_time=1:设置慢查询阈值(1s),超过该时间的SQL记录到慢查询日志。

    • expire_logs_days=7:设置二进制日志保留时间(7天),自动清理过期日志,避免磁盘满。

  • 连接配置:

    • max_connections=1000:设置最大连接数,根据业务量调整,避免连接数不足导致无法连接。

    • wait_timeout=600:设置连接超时时间(10分钟),自动关闭空闲连接,释放资源。

  • InnoDB优化:

    • innodb_flush_log_at_trx_commit=1:每次事务提交时,将日志写入磁盘,保证数据一致性(牺牲部分性能,适合对数据一致性要求高的场景)。

    • innodb_log_file_size:InnoDB日志文件大小,建议设置为1-2G,减少日志切换频率,提升性能。

    • innodb_file_per_table=1:每个表单独生成一个ibd文件,便于管理和维护,避免单文件过大。

3.2 SQL优化(核心优化方向)

3.2.1 索引优化

  • 创建合适的索引:主键索引(必填)、唯一索引(用于唯一约束,如手机号、身份证)、联合索引(用于多条件查询,遵循"最左前缀原则",将查询频率高的字段放在前面)。

  • 避免索引失效:

    • 不使用函数操作索引字段(如where DATE(create_time) = '2026-04-01',改为where create_time between '2026-04-01 00:00:00' and '2026-04-01 23:59:59')。

    • 不使用模糊查询%开头(如where name like '%张三',改为where name like '张三%',后者可使用索引)。

    • 避免索引字段类型不匹配(如字段为int,查询时用字符串匹配,如where id = '123')。

  • 定期维护索引:删除无用索引(未被使用的索引,可通过sys.schema_unused_indexes查看)、优化碎片化索引(optimize table 表名;)。

3.2.2 SQL语句优化

  • 避免全表扫描:尽量使用索引查询,避免select *,只查询需要的字段,减少数据传输量。

  • 优化多表连接:尽量使用inner join(内连接),避免left join/right join(外连接),若必须使用外连接,确保关联字段有索引;减少连接表的数量(建议不超过3张表)。

  • 避免子查询:子查询效率较低,可改为关联查询(join),如select * from user where id in (select user_id from order),改为select u.* from user u join order o on u.id = o.user_id

  • 避免批量操作:批量insert、update、delete时,分批次执行(如每次1000条),避免一次性操作导致锁表、服务器压力过大。

  • 使用limit限制返回行数:查询时使用limit,避免返回大量数据(如select * from user limit 100)。

3.3 表结构优化

  • 选择合适的数据类型:尽量使用占用空间小的数据类型,如用int代替varchar(存储数字)、用tinyint代替int(存储0-255的数字)、用datetime代替varchar(存储时间),减少磁盘占用和内存消耗。

  • 避免字段冗余:不重复存储相同的数据(如用户表和订单表,不重复存储用户名,通过用户ID关联),减少数据更新时的一致性问题。

  • 分表分库:当单表数据量超过百万级,查询性能会明显下降,可进行分表(水平分表:按时间、用户ID拆分;垂直分表:将大表拆分为多个小表,按字段拆分);当数据库压力过大,可进行分库(按业务模块拆分)。

  • 使用分区表:对于时间范围相关的表(如订单表、日志表),使用分区表(如按月份分区),查询时只扫描对应分区,提升查询效率,便于数据归档。

3.4 服务器与环境优化

  • 硬件优化:提升服务器CPU核心数、内存大小,使用SSD磁盘(相比机械硬盘,IO速度提升10倍以上),减少磁盘IO瓶颈。

  • 操作系统优化:关闭不必要的服务,释放系统资源;调整内核参数(如调整TCP连接数、IO调度算法),优化网络和磁盘性能。

  • 数据库架构优化:搭建主从复制(一主多从),主库负责写操作,从库负责读操作,分担主库压力;搭建集群(如MySQL Cluster、MGR),提升高可用性和并发处理能力。

四、常用排查与优化命令汇总

4.1 基础状态查询命令

  • 查看MySQL版本:select version();

  • 查看当前连接数:show global status like 'Threads_connected';

  • 查看最大连接数:show variables like 'max_connections';

  • 查看慢查询日志状态:show variables like '%slow_query%';

  • 查看当前运行进程:show processlist;

  • 查看InnoDB状态:show engine innodb status;

  • 查看表结构:show create table 表名;

  • 查看索引:show index from 表名;

4.2 性能分析命令

  • 分析SQL执行计划:explain SQL语句;

  • 查看SQL执行耗时:set profiling=1;(开启 profiling),执行SQL后,show profiles;(查看所有SQL耗时),show profile for query 进程ID;(查看具体SQL的执行细节)。

  • 分析慢查询日志:pt-query-digest 慢查询日志文件(需安装percona-toolkit工具),生成慢查询统计报告。

4.3 优化操作命令

  • 创建索引:create index 索引名 on 表名(字段名);(普通索引)、create unique index 索引名 on 表名(字段名);(唯一索引)、create index 索引名 on 表名(字段1,字段2);(联合索引)。

  • 删除索引:drop index 索引名 on 表名;

  • 优化表:optimize table 表名;(优化表结构和索引,释放碎片空间)。

  • 清理二进制日志:purge binary logs before '2026-04-01 00:00:00';

  • 杀死进程:kill 进程ID;

五、注意事项

  • 生产环境禁止直接修改配置文件和执行高危操作,需先在测试环境验证,再灰度发布。

  • 定期备份数据(全量备份+增量备份),避免数据丢失,备份后需验证备份文件的可用性。

  • 定期监控数据库状态(CPU、内存、IO、连接数、慢查询),建立预警机制,提前发现问题。

  • SQL优化需结合业务场景,不能只追求性能,还要保证数据一致性和业务正确性。

  • 定期维护数据库(清理日志、优化索引、检查表结构),避免碎片化和性能退化。

  • 遇到复杂故障,优先排查基础问题(服务、网络、磁盘、配置),再深入排查SQL和数据问题,必要时联系MySQL官方支持或专业运维人员。

相关推荐
天草二十六_简村人2 小时前
阿里云的NAT和弹性公网IP,解决ECS机器访问外网的实现方案
运维·后端·网络协议·阿里云·云计算·ip
rrrjqy2 小时前
Redis常见问题(一)
数据库·redis·缓存
Humbunklung2 小时前
WMO 天气代码(Code Table 4677)深度解析与应用报告
开发语言·数据库·python
道清茗2 小时前
【MySQL知识点问答题】锁机制、索引优化与数据库恢复方法
数据库·mysql
kaoa0002 小时前
Linux入门攻坚——73、运维OS Provisioning阶段工具之PXE、Cobbler
linux·运维
hero.fei2 小时前
排查redis出现报错ERR redis temporary failure
数据库·redis·缓存
东北甜妹2 小时前
MYSQL
运维
野犬寒鸦2 小时前
MySQL复习记录Day01
数据库·后端
A.A呐2 小时前
【Linux第二十三章】传输层
linux·运维·服务器