慢查询如何“拖垮”业务?
慢查询不仅仅是“一个查询跑得慢”,它通过以下链式反应对业务造成毁灭性打击:
1.耗尽数据库连接资源: 每个执行中的SQL都会占用一个数据库连接。慢查询长时间不释放连接,当并发请求到来时,新的业务请求将因无法获取连接而等待或失败,导致应用层抛出ConnectionTimeout或ConnectionPoolExhausted异常。
2.抢占CPU/I/O资源: 复杂的查询(如全表扫描、排序、临时表操作)会持续消耗大量的CPU周期和磁盘I/O带宽。这直接“饿死”了其他正常查询,使整个数据库实例性能骤降。
3.引发锁竞争(尤其是MySQL/InnoDB): 长时间的查询(特别是未走索引的更新操作)可能持有行锁、间隙锁甚至表锁,导致其他会话被阻塞,形成锁等待链,业务出现大面积卡顿。
找到“元凶”SQL,并理解其为什么慢。
专业操作步骤:
启用并分析慢查询日志(Slow Query Log):
关键配置(MySQL示例):
slow_query_log = 1slow_query_log_file = /var/lib/mysql/slow.loglong_query_time = 1.0 # 定义“慢”的阈值(单位:秒),建议从1秒开始,逐步收紧至0.1秒。log_queries_not_using_indexes = 1 # 捕获未使用索引的查询,非常重要!log_throttle_queries_not_using_indexes = 100 # 避免日志被刷爆
分析工具: 使用 mysqldumpslow 或更强大的 pt-query-digest (Percona Toolkit) 对慢查询日志进行聚合分析。
bashpt-query-digest /var/lib/mysql/slow.log > slow_report.txtpt-query-digest
会生成一份报告,列出:
1.最耗时的查询(按总时间排序)
2.执行次数最多的查询
3.最锁表的查询
实时数据库诊断:
查询进程列表: SHOW FULL PROCESSLIST; 查看当前正在执行的所有SQL,观察是否有长时间处于 "Sending data", "Copying to tmp table", "Sorting result" 状态的查询。
利用性能模式(Performance Schema)和 sys Schema: (MySQL 5.7+/8.0+)
sql-- 查找哪些SQL消耗了最多的总时间SELECT * FROM sys.statement_analysis ORDER BY total_latency DESC LIMIT 10;-- 查看全表扫描最多的语句SELECT * FROM sys.statements_with_full_table_scans LIMIT 10;
解剖单个慢查询:使用 EXPLAIN(执行计划)
将抓到的慢SQL,在前面加上 EXPLAIN (或 EXPLAIN FORMAT=JSON) 来查看其执行计划。
关注以下字段:
1.type: 访问类型。性能从优到劣:system > const > eq_ref > ref > range > index > ALL(全表扫描,必须优化)。
2.key: 实际使用的索引。如果为NULL,说明未使用索引。
3.rows: 预估需要扫描的行数。这个值越大,性能越差。
4.Extra: 额外信息。出现 Using filesort(文件排序)、Using temporary(使用临时表)通常是性能杀手。