新闻详情

新闻详情

首页 / 资讯中心 / 详情

数据库变慢如何排查?五大必看环节助你快速定位性能瓶颈

发布时间:2026/9/28 13:17:28来源:尧图网络
数据库变慢如何排查?五大必看环节助你快速定位性能瓶颈
1. 先弄清楚“数据库变慢”到底慢在哪一环先说个很真实的场景。半夜两点收到告警说数据库响应时间从 20ms 飙到了 800ms链路监控上整个接口的耗时长了一大截。这个时候如果直接冲到服务器上看 CPU、看内存、看磁盘大概率会被一堆指标绕晕。因为“数据库慢”这四个字本身就是个黑盒你看到的只是现象真正的瓶颈可能藏在好几层中间件后面。我干了这么些年数据库运维最深的体会是排查性能问题第一步永远是定位“慢在哪个环节”而不是急着看某个指标。1.1 五种最常见的线上表现线上数据库变慢通常逃不出下面五种表现接口响应时间变长这是业务方最先感知到的特征是整体超时率上升但数据库 CPU 未必高。数据库 CPU/IO 打满监控面板上某个单点指标跑满内核日志里大量 task 阻塞。并发连接数暴涨连接数超过阈值后新连接进不来表现为数据库“拒绝连接”。主从延迟暴涨主库没事从库跟不上读多写少的业务会大量命中从库然后超时。特定 SQL 突然变慢原来执行只要 10ms 的 SQL 变成 10s页面上某些功能点开就卡。这五种表现对应的排查方向完全不一样。如果你连“慢”属于哪一类都没有判断清楚就开始优化索引、调参数很容易白忙活。1.2 我自己的排查顺序与记录习惯我个人有一套固定的打法碰到数据库慢先看这五个地方顺序基本固定第一看慢查询日志找最刺眼的 SQL第二看锁等待看有没有堵车第三看连接数与会话堆积第四看索引和统计信息是否失效第五看系统资源和主从延迟。这套顺序不是随便定的它的逻辑是“从业务影响面最大的点往底层影响面最小的点”推。慢查询直接影响用户体验锁等待和连接堆积影响系统可用性索引和统计信息影响的是单条 SQL 的效率而系统资源通常只是前面问题的“果”而不是“因”。另外我强烈建议养成一个习惯每次排查完把时间、现象、根因、处理手段、持续时间记在一个小本本上。别嫌麻烦。数据库性能问题的特点是“同样的表象完全不同的病因”你上个月遇到的那个高 CPU 事件和这个月的高 CPU 事件根因可能是两个方向。记录多了之后你会发现自己判断问题越来越快。2. 第一个必看位置慢查询日志里的“抄底SQL”慢查询日志是数据库性能排查的第一站没有之一。它相当于飞机的黑匣子记录着每一个执行时间超过阈值的 SQL 语句。线上数据库卡大概率有某条 SQL 在拖后腿。2.1 慢查询日志怎么开、参数怎么设才合理MySQL 里和慢查询相关的参数主要有三个-- 查看当前慢查询配置 SHOW VARIABLES LIKE slow_query_log%; SHOW VARIABLES LIKE long_query_time; SHOW VARIABLES LIKE log_queries_not_using_indexes;slow_query_log是否开启慢查询日志线上一定要设为 ON。long_query_time阈值单位秒。默认是 10 秒这个值在实践中太宽松了。对于一个正常业务系统超过 1 秒的 SQL 就已经值得关注了。我一般建议从小流量业务开始设 1核心交易库可以更严格设 0.5。log_queries_not_using_indexes记录所有不走索引的 SQL。这个参数很有价值很多慢 SQL 在变成慢 SQL 之前最早是从“没走索引”开始的。动态修改命令是SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1; SET GLOBAL log_queries_not_using_indexes ON;注意long_query_time修改之后已经存在的连接不会立即生效不影响新连接。如果你用的是云数据库很多云厂商默认已经开启了慢查询只是阈值可能比较大记得手动调小。2.2 定位到 SQL 之后我每次必做的三件事找到慢 SQL 列表只是开始真正的工作在拿到具体语句之后第一件事看执行计划。EXPLAIN SELECT * FROM order WHERE user_id 123 AND create_time 2025-01-01;我会重点看type字段、key字段和rows字段。type是ALL说明全表扫描key是NULL说明没走到索引rows如果比预期大几个数量级说明估算严重不准。这三个字段基本能告诉你这条 SQL 为什么慢。第二件事把 SQL 的过滤条件拆开分析。看 WHERE 后面的每个条件是否独立能走索引看 ORDER BY、GROUP BY 是否触发了 filesort 或临时表。很多时候慢 SQL 不是单条件有问题而是多个条件组合导致索引选择失败。第三件事回归到业务的真实访问模式。这是我踩过坑之后学乖了的地方。一条 SQL 慢有时候不是 SQL 本身写得差而是业务方在拿一个 OLTP 库跑 OLAP 式查询比如一次性查半年的流水做报表或者用SELECT *拉几万行到应用层做内存计算。这种时候你在数据库层怎么优化都有上限正确的做法是拉着业务方一起聊清楚需求边界引导他们用离线数仓或者改变查询方式。慢查询日志的分析我建议不要一条条人肉看线上慢 SQL 一多人肉根本看不过来。可以定期做聚合比如用pt-query-digest这类工具按 SQL 指纹聚合把同类型的慢查询归并统计一眼就能看出哪类模子的 SQL 出现频率最高、累计耗时最长。提示pt-query-digest是 Percona Toolkit 里的一个工具分析慢查询日志非常好用。它能按响应时间、执行次数、总耗时排序直接输出 Top N 模板省掉大量人工翻日志的时间。3. 第二个必看位置锁等待与阻塞链如果慢查询日志里找不到特别离谱的 SQL或者找到了但优化完之后问题依然在那就要考虑锁等待了。锁这个东西很有意思它造成的现象是“数据库整体变慢”但你去看单条 SQL每条单独执行都快得很。因为 SQL 本身不慢慢的是它在排队等锁。3.1 怎么看锁等待、怎么区分行锁表锁MySQL InnoDB 引擎的行锁机制简单理解就是事务 A 锁住了某一行数据没提交事务 B 想要修改同一行就只能等。这个等待时间一长业务上就表现为更新卡住、接口超时。遇到卡顿先问自己两个问题是行锁还是表锁是读阻塞还是写阻塞在 MySQL 8.0 里可以直接查performance_schema中的锁等待信息SELECT * FROM performance_schema.data_lock_waits; SELECT * FROM performance_schema.data_locks;8.0 之前的版本没有这些表但可以用SHOW ENGINE INNODB STATUS看事务列表虽然可读性差一点不过里面会打印出等待锁的 SQL 和持有锁的事务。另外还有一个非常实用的表——sys.innodb_lock_waitsSELECT * FROM sys.innodb_lock_waits;它会直接告诉你哪个事务在等哪个锁以及这个锁的等待时间和被阻塞的 SQL 文本排查起来比直接翻原始状态快太多。3.2 真实案例一条 UPDATE 卡死整张业务表的排查我印象很深的一次事故业务方报障说订单系统写库特别慢下单接口超时率飙到 30% 以上。查慢查询没有明显慢 SQLCPU 也很正常但sys.innodb_lock_waits里显示有二十多个事务都在等同一把锁。顺着锁等待信息找到持有锁的事务发现是一张报表的定时任务在凌晨跑批事务长时间未提交导致后续所有对该表的写操作全部排队。最终定位到的原因就很搞笑跑批任务里有一段逻辑把事务打开了但没 commit 就退出了连接也没释放锁被一直攥在手里。当时的处理步骤找到持锁的会话 ID和业务方确认不是正在执行的关键逻辑确认可以打断执行KILL杀掉持锁会话让业务方修复跑批代码补上COMMIT或ROLLBACK。因为每晚都可能重跑这个坑如果不从代码层面堵住第二天会准时复发。锁等待这个问题的排查难点在于它涉及的是多个事务之间的互动关系单看任何一方都不完整。一个事务握着锁不撒手另一个事务干着急你得把整个“锁等待链路”串起来看才会看到全貌。4. 第三个必看位置连接数暴涨与会话堆积锁问题排查完之后下一个要确认的是连接数。在数据库层面有个很常见的“假慢”现象数据库本身性能没毛病但连接池满了应用端拿到不到连接超时于是业务感知就是“数据库变慢”。4.1 连接池参数、活跃连接数与线程跑满先看几个核心指标Threads_connected当前有多少连接Threads_running当前有多少连接正在执行语句max_connections最大允许连接数Connection_errors_max_connections有多少次因为连接数满而被拒绝的连接请求。SHOW STATUS LIKE Threads_connected; SHOW STATUS LIKE Threads_running; SHOW VARIABLES LIKE max_connections;为什么会连接数暴涨通常有三类原因应用连接池设置过大比如一个 Java 应用配了 200 个连接十个应用实例就是 2000 个连接数据库max_connections只有几百瞬间打满。应用侧连接泄漏连接没正确归还到池子里导致连接池被耗尽应用层不断尝试新建连接形成恶性循环。某条 SQL 阻塞导致连接堆积连接进来了但事务一直不提交新请求只能继续创建连接往库里挤最终把数据库连接数压爆。4.2 会话堆积的快速止血与根因处理连接数暴涨这种场景我的建议是一定要先止血再聊根因。止血操作分两步第一步把应用方的连接池参数落到一个合理的范围。别想着一次性把所有应用实例的连接数都调上来数据库承载的连接总数是有上限的。第二步把异常会话杀掉。注意不是说所有堆积的会话都要杀而是要识别哪些会话是真正的坏会话。判断方法很简单State在Sleep、且持续很长时间不释放、事务没有提交的多半是异常会话。-- 查看异常会话 SELECT id, user, host, db, command, time, state, info FROM information_schema.processlist WHERE command Sleep AND time 100;但这种操作一定要谨慎。先确认这些会话背后没有正在运行的关键业务再确认是不是应用连接池里健康保活的连接。保活的空闲连接是正常的不代表有问题。等止血完成之后再往回倒退查应用日志、查慢查询、查锁等待找到最初始的根因把问题彻底堵住。我见过很多团队只做了止血没管根因第二天同一时间同一症状准时复发那就很被动了。5. 第四个必看位置索引失效和执行计划偏移聊完负载层面的问题再往细了说。很多时候数据库变慢是某条核心 SQL 的执行计划变了从走索引变成全表扫描。这类问题最要命的地方在于它不是突然出现的而是慢慢恶化的。今天慢 100ms明天慢 500ms后天 2 秒你没点对比数据根本感知不到恶化趋势。5.1 常见索引失效场景别只盯着类型转换一提到索引失效很多人第一反应就是“查询字段上用了函数导致索引失效”。这个没错但它只是众多坑里的一个。我实际开发中遇到比较多的还有这么几类第一类隐式类型转换。比如表里user_id是 bigint查询条件却传了一个字符串123。MySQL 有隐式类型转换的规则如果字段类型和参数类型不一致有时能走到索引有时走不到完全看优化器怎么想。这种情况我建议在应用层就把类型转换做掉不要指望数据库帮你判断。-- 不推荐user_id 为 bigint传入字符串 SELECT * FROM user_order WHERE user_id 123; -- 推荐直接传数值类型或在SQL中明确类型 SELECT * FROM user_order WHERE user_id 123;第二类字符集不一致导致的无法索引关联。这个坑隐蔽性极强。两张表关联字段都是 varchar但表结构一个是 utf8mb4 一个是 latin1关联时 MySQL 需要做字符集转换结果就是索引失效。这种问题在 ER 图上完全看不出来只有执行计划出来之后才能看到转换的痕迹。第三类前导模糊匹配。LIKE %关键词%这种写法因为没法利用 B 树的顺序特性只能扫全表。如果业务真要靠中间匹配可以评估全文索引或者上专门的搜索引擎不要把压力全丢给数据库。第四类OR 条件混用。一个 OR 条件里如果某个分支不能走索引整个查询可能退化成全表扫描。比如WHERE id 123 OR status 1如果status上没有索引优化器会放弃id上的索引去扫全表。这种情况可以改写为UNION ALL或者给两个条件都建上合适的索引。5.2 统计信息过期导致的执行计划漂移执行计划漂移是“数据库变慢”里最难排查的一类因为它不是代码变了不是数据量大规模涨了也不是索引被删了纯粹是优化器基于过期的统计信息做出了错误的判断。MySQL 里通过ANALYZE TABLE来重新采集统计信息ANALYZE TABLE user_order;建议在数据量发生明显变化之后手动触发一次。依赖自动采样的话部分长时间跑批后数据量翻倍的场景统计信息跟不上变化的速度。如何确认是执行计划漂移方法很简单-- 执行一次记录执行时间 SELECT * FROM user_order WHERE user_id 123 AND create_time 2025-01-01; -- 再强制走某个索引对比 SELECT * FROM user_order FORCE INDEX (idx_user_time) WHERE user_id 123 AND create_time 2025-01-01;如果强制走索引之后速度大幅度提升那基本可以确定是优化器选了错误的执行计划。接下来要看是不是统计信息过期重新ANALYZE之后如果恢复正常那就没问题。如果反复漂移可能需要你手动干预比如调整optimizer_switch或者通过FORCE INDEX固定执行计划。但这里有个经验之谈不要一遇到慢 SQL 就想着固定执行计划。固定了这条路如果将来数据量继续变大或者索引结构变了固定的计划一样会变成坏计划。要先理解为什么优化器做了这个选择再从统计信息、索引设计、SQL 写法三个维度找平衡。6. 第五个必看位置系统资源与主从延迟前面四处都排查完还没找到问题或者问题已经定位到某一块了但对不上号这个时候再去看系统层面CPU、磁盘 IO、内存、网络、主从延迟。很多 DBA 新手习惯于先看资源再看日志这种顺序其实容易误判。资源的异常往往是某个具体问题的表现而不是起因先看日志锁定目标再回来看资源会快很多。6.1 CPU、磁盘IO、内存怎么联动分析CPU 高不一定需要扩容。我就遇到过 CPU 跑到 90% 以上结果是某个 SQL 在做大量逻辑读因为索引没命中一次查询扫描了几千万行。这个时候加 CPU 一点用没有把索引建上CPU 自己就降下来了。判断逻辑很简单如果 CPU 高但磁盘 IO 很低多半是逻辑读问题也就是 SQL 扫描行数太多或者计算量太大如果 CPU 高且磁盘 IO 也很高那是物理读问题可能数据不在内存里需要频繁读盘如果 CPU 不高但磁盘 IO 打满那一般是刷脏页或者大事务落盘导致的。命令示例以最常见的 Linux 系统为例# 看CPU和IO整体情况 top # 看磁盘IO是不是打满 iostat -x 3 # 看数据库进程的线程状态 pidstat -t -p mysqld_pid 2内存方面不要只看剩余内存要看 InnoDB Buffer Pool 的命中率。一个容易忽略的点是内存明明还有很多但 Buffer Pool 太小导致热数据无法缓存频繁发生磁盘读。这种场景加内存、调大innodb_buffer_pool_size往往立竿见影如果命中率已经接近 99% 了那再加意义也不大。6.2 主从延迟的排查次序主从延迟是一个特别容易被误当成“数据库变慢”的问题。现象上完全一致应用查询读的是从库从库延迟大查询到的数据不新鲜或者从库应用回放跟不上导致查询请求堆积。如果业务架构上有读写分离排查顺序一定不要乱。第一步先看延迟时间是多长SHOW SLAVE STATUS;重点看Seconds_Behind_Master这个字段。如果这个值是 0那说明从库回放正常问题不在主从。第二步如果延迟很大看协程/线程的状态。是单线程复制还是多线程复制大事务是不是导致回放变慢了这里有个很典型的问题主库上执行了一小时的批量更新从库只有一个 SQL 线程在回放延迟就会逼近一小时。这种场景下从库的 CPU 反而不会太高因为它在慢慢处理一条大事务。第三步确认延迟持续的时间窗口和业务高峰是否吻合。如果延迟只在特定时间段出现比如凌晨跑批时固定出现那基本是跑批任务造成的。如果不是固定窗口而是随机延迟则需要检查网络延迟、从库机器性能、以及是否有其他慢查询在抢占从库资源。主从延迟的根因千奇百怪但排查的框架不外乎上面三步剩下的就是往框架里填具体证据。7. 几个实战下来容易忽略的点最后分享几个排查中容易踩的坑这些细节用钱都不一定能买到基本都是靠一次次被线上故障教育出来的。第一别忽略“看起来不慢”的 SQL。慢查询日志设置的阈值是 1 秒但一条执行 900ms 的 SQL 如果每天被调用一百万次哪怕它不进入慢查询统计对整个系统的压力也一样巨大。排查性能问题单看单条 SQL 的耗时是不够的要看整体 QPS 和单条 SQL 耗时的乘积。高频次的中低耗时 SQL优化后的收益往往比低频次的超慢 SQL 更大。第二事务隔离级别会影响锁行为。很多人排查死锁和锁等待的时候默认用的是 REPEATABLE READ这个隔离级别下间隙锁Gap Lock的行为更复杂。如果你业务确实允许且场景合适切到 READ COMMITTED 可以减少不少锁冲突。但切换前一定要充分评估业务语义不能只看性能。第三业务高峰期的自动运维操作要格外小心。我遇到过好几次“数据库突然变慢”最后定位原因是运维平台在高峰期自动执行了批量ANALYZE或者自动发起了全库逻辑备份占了大量 IO。这种问题从数据库日志看不出来只能通过窗口期对比和运维审计日志来定位。第四连接数不等于并发度。有很多数据库连接数显示几千但真正活跃执行的Threads_running只有十几个。连接数多不丢人可怕的是Threads_running长时间很高。高并发会话数有限的数据库性能问题大概率出在执行计划或锁上而不是连接池配置上。第五看数据增长趋势。数据库今天慢不代表今天才出问题。排查时把近七天甚至近三十天的数据量和慢查询日志趋势拉出来对比很多问题其实在几天前就有苗头了。性能问题最好的处理时机是在它产生线上影响之前。数据库诊断这件事越往后越觉得“功底”比“技巧”重要。技巧是那些让人眼前一亮的具体手段功底则是知道什么时候该用哪个技巧、用完之后怎么验证、验证之后怎么防止复发。上面这五个检查点是我个人这几年做线上问题处理时最先看的地方说不上高深但确实在一次次告警中帮我快速从“不知道哪里有问题”走到了“确认了问题在哪”。如果你有自己的排查顺序和踩坑经历强烈建议也梳理成一套自己固定的步骤。把排查流程规范下来比每次遇到问题临时拍脑袋要靠谱得多尤其在凌晨两点被叫起来的时候。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

如何看懂 AgentENV 系统架构全景图:从 API 到 Firecracker 微虚拟机的完整数据流 2026/9/28 20:16:44

如何看懂 AgentENV 系统架构全景图:从 API 到 Firecracker 微虚拟机的完整数据流

如何看懂 AgentENV 系统架构全景图:从 API 到 Firecracker 微虚拟机的完整数据流 【免费下载链接】AgentENV AgentENV (AENV) is a distributed platform for running agent environments at scale. 项目地址: https://gitcode.com/gh_mirrors/age/AgentENV …

阅读更多 →
STRATUS:面向现代云的自治可靠性工程多智能体系统 2026/9/28 20:16:44

STRATUS:面向现代云的自治可靠性工程多智能体系统

STRATUS: A Multi-agent System for Autonomous Reliability Engineering of Modern Clouds 状态: Finished Publisher: NeurIPS Publishing/Release Date: 2026年3月19日 Summary: STRATUS 用检测、诊断、缓解、撤销四类智能体和状态机编排实现自治 SRE;以 Transac…

阅读更多 →
让AI海报看起来像真的印出来的:mono-color-skill网点与孔版复制质感完全解析 2026/9/28 20:16:44

让AI海报看起来像真的印出来的:mono-color-skill网点与孔版复制质感完全解析

让AI海报看起来像真的印出来的:mono-color-skill网点与孔版复制质感完全解析 【免费下载链接】mono-color-skill One-ink editorial print image skill — warm paper, halftone photography, active negative space, and restrained typography. 项目地址: https…

阅读更多 →
智谱开源 GLM-5.2:744B 参数、100 万上下文,国产编程模型在赌什么 2026/9/28 20:16:44

智谱开源 GLM-5.2:744B 参数、100 万上下文,国产编程模型在赌什么

先把事情说清楚:智谱上线并开源了新一代旗舰大模型 GLM-5.2,官方把它定位成"面向长任务时代的旗舰模型",主打两件事——一是真正可用的 100 万 token 上下文,二是编码与长程任务能力。模型权重以 MIT 协议开放。近期随着…

阅读更多 →
一个LangGraph实战案例:TradingAgents-Astock 12阶段分析流水线的完整代码拆解 2026/9/28 20:16:44

一个LangGraph实战案例:TradingAgents-Astock 12阶段分析流水线的完整代码拆解

一个LangGraph实战案例:TradingAgents-Astock 12阶段分析流水线的完整代码拆解 【免费下载链接】TradingAgents-astock A股多Agent投研框架 — 适配A股数据源(龙虎榜/游资/解禁等),7位分析师基于A股规则的辩论决策,基于TradingAgents深度改造…

阅读更多 →
非阻塞状态机实现薄膜按键去抖:JS验证与C语言移植要点 2026/9/28 20:16:37

非阻塞状态机实现薄膜按键去抖:JS验证与C语言移植要点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉