从 配置、SQL、连接、存储引擎、程序、操作系统 六个方向排查
SQL查询过程:
先查缓冲池 ,若在则直接读取,反之则查询磁盘并将磁盘数据放到缓冲池以供下次查询使用
@[TOC]1.缓冲池优化·增加缓存提高查询速度
#查询缓存大小showvariableslike'innodb_buffer_pool_size'#设置缓存(1G=1073741824字节)setglobalinnodb_buffer_pool_size=1073741824#注意上面设置方式重启后会失效**#永久设置方式:修改my.ini文件中的 innodb_buffer_pool_size 值大小(记得重启服务)
**
大小设置建议:物理内存的80%
2. 慢SQL
-- 1. 查看占用内存最高的执行语句SELECTquery,exec_count,total_latency,avg_examined_rowsFROMsys.statement_analysisORDERBYtotal_latencyDESCLIMIT10;# 查询正在执行的、消耗资源较多的 SQL:SELECT*FROMsys.statement_analysisORDERBYtotal_latencyDESCLIMIT10;-- 2. 查看哪些线程当前正在占用大量内存SELECTthread_id,processlist_id,current_used_mem_mbFROMsys.memory_thread_by_current_bytesWHEREcurrent_used_mem_mb>50;-- 查找占用超过50MB的线程--- 定位正在运行的“慢”过程 (如果内存正在飙升,立即查看当前正在运行的 SQL)-- 查看当前正在执行的线程,观察 Time 和 InfoSHOWFULLPROCESSLIST;--关注点: Time 很长且 Command 为 Query 的语句;以及 State 显示为 Copying to tmp table 或 Sending data 的语句。#慢SQL开启-- 开启慢查询日志功能SETGLOBALslow_query_log='ON';-- 设置慢查询的判定阈值(单位:秒,建议先设为 1 或 2,视业务情况而定)SETGLOBALlong_query_time=1;-- 设置日志输出路径(通常在数据目录下)-- SET GLOBAL slow_query_log_file = '/var/lib/mysql/mysql-slow.log';#验证SHOWVARIABLESLIKE'slow_query_log';SHOWVARIABLESLIKE'long_query_time';永久开启,修改 MySQL 的配置文件(my.cnf 或 my.ini)
[mysqld]# 开启慢查询日志slow_query_log=1# 设置慢查询时间阈值(超过此时间会被记录)long_query_time=1# 日志文件路径(确保 MySQL 用户对该路径有写权限)slow_query_log_file=/var/lib/mysql/mysql-slow.log# 记录未使用索引的查询(可选,建议开启)log_queries_not_using_indexes=13. 排查手段
# 查看操作系统内存占用1.使用top或htop查看 RES(常驻内存)和 SHR(共享内存)2.观察free-m,注意 buff/cache 是否过高。MySQL 依赖系统缓存,这部分高通常是正常的#查看 MySQL 内部内存分配-- 查看各内存分类的占用情况SELECT*FROMsys.memory_global_by_current_bytes;-- 查看哪些线程占用了较多内存SELECT*FROMsys.memory_thread_by_current_bytes;#排查配置问题-- 查看所有相关内存参数SHOWVARIABLESWHEREVariable_nameIN('innodb_buffer_pool_size','innodb_log_buffer_size','sort_buffer_size','join_buffer_size','read_buffer_size','max_connections');核算逻辑:
- 全局内存 = innodb_buffer_pool_size + innodb_log_buffer_size + …
- 单连接内存 = sort_buffer_size + join_buffer_size + read_buffer_size + …
- 总预估内存 = 全局内存 + (max_connections × 单连接内存)
注意: 不能超过了服务器物理内存的 80%
@[TOC]################# 优先排查 ######################
- 实时“抓现行”
#这条命令能列出当前 MySQL 实例中所有正在运行的线程SHOW FULL PROCESSLIST;核心列:
- Time:该线程执行了多久(单位:秒)。如果数值很大且状态不是 Sleep,说明该 SQL 执行时间过长
- State:线程当前正在做什么(重点关注: Sending data(可能正在从磁盘读取大批量数据)、Copying to tmp table(正在创建临时表,极度消耗内存)、Sorting result(正在排序,消耗 CPU 和内存))
- info:当前执行的完整 SQL 语句。如果语句很长,FULL 关键字能保证你看到完整内容,而不是被截断。
典型场景:
如果你发现某一行的 Time 很高,且 State 为 Sending data,这通常就是那个正在“吃掉”内存的 SQL。
- 查历史帐
你可以运行以下语句查看前 10 条最耗资源的 SQL:
SELECTquery,exec_count,-- 执行次数total_latency,-- 总耗时avg_examined_rows,-- 平均扫描行数(重点关注)rows_sent_avg,-- 平均返回行数tmp_tables,-- 使用临时表的次数(内存杀手!)disk_tmp_tables-- 使用磁盘临时表的次数FROMsys.statement_analysisORDERBYtotal_latencyDESCLIMIT10;@[TOC]4.max_connections(最大连接数)
-- 当前连接数SHOWSTATUSLIKE'Threads_connected';-- 当前正在执行的连接SHOWSTATUSLIKE'Threads_running';-- 历史最大连接数SHOWSTATUSLIKE'Max_used_connections';-- 最大连接数配置SHOWVARIABLESLIKE'max_connections';-- 是否发生连接数耗尽SHOWSTATUSLIKE'Connection_errors_max_connections';-- 查看所有连接SHOWFULLPROCESSLIST;-- 按状态统计连接SELECTCOMMAND,COUNT(*)FROMinformation_schema.PROCESSLISTGROUPBYCOMMAND;-- 按用户统计连接SELECTUSER,COUNT(*)FROMinformation_schema.PROCESSLISTGROUPBYUSER;#1.查看当前连接数,Threads_connected:表示当前有多少个客户端连接到 MySQLSHOW STATUS LIKE'Threads_connected';#2.再看真正执行 SQL 的连接:SHOW STATUS LIKE'Threads_running';# Threads_running 4#说明:#58 个连接#真正工作的只有 4 个#其它 54 个都是 Sleep,这是正常现象#3.查看历史最大连接数SHOW STATUS LIKE'Max_used_connections';# Max_used_connections 100 表示自 MySQL 启动以来,最多只用过 126 个连接。#4.再看SHOW VARIABLES LIKE'max_connections';#max_connections = 10001000↓ 历史最高126配置过大。#5.看连接是否打满SHOW STATUS LIKE'Connection_errors_max_connections';#6.查看连接详情SHOW FULL PROCESSLIST;