文档首页> 技术教程> 数据库慢拖垮整站:现象与定位

数据库慢拖垮整站:现象与定位

发布时间:2026-05-01 11:31        更新时间:2026-05-02 07:25
晚上十点收到告警,网站还能打开,但每个页面都要转十几秒,登录和下单全部超时。登上去看,CPU 没跑满,内存也充裕,最后发现是一条没走索引的统计 SQL 把数据库拖住了。数据库一慢,慢的从来不只是数据库。 一、慢是怎么传导的 Web 应用处理请求时,几乎每个环节都要查库。一条查询本来 10 毫秒,慢到 10 秒之后,Web 进程会一直等在那里不释放。并发一上来,进程池被占满,新请求只能排队;应用靠连接池连数据库的话,数据库连接也会被这些慢查询全部占住,后面的请求要么排队,要么直接报"获取连接超时"。于是表现就成了整站变慢、接口报错,而根子只在一条 SQL。CPU 反而看不出来,因为等待不算计算量,这也是数据库类故障容易被误判的原因。 二、先看连接堆积 登录服务器,用 mysql -uroot -p 进入数据库后跑 show processlist;,重点看 Time 列超过几秒的查询,以及 State 列里带 Lock 状态的行。想看语句原文用 show full processlist;,Info 列会给出完整 SQL,方便定位到代码里的位置。再看堆积程度:show status like 'Threads_running';,正常业务下这个值通常在个位数到十几,飙到几百就说明查询在大量堆积。应用侧的连接池监控如果出现 connection timeout,就是连接池被占满的直接证据。 三、把慢查询抓出来 临时开启慢查询日志,不用重启服务: SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; 超过 1 秒的查询会写进日志,路径用 show variables like 'slow_query_log_file'; 查到。收集一段时间后,用 mysqldumpslow -s t /路径/主机名-slow.log | head -20 排出最耗时的几条,逐条用 EXPLAIN 检查:key 列是 NULL、rows 接近全表行数,就是没走索引,回到建索引或改写语句上解决。 四、止损要有顺序 线上正卡着的时候,顺序比手段重要。先 kill 掉执行时间最长、状态为 Sending data 或 Waiting for lock 的查询止血,写法是 KILL 查询Id;,Id 就是 processlist 第一列的数字;再对非核心功能临时限流或关闭;最后才是重启应用释放连接池。直接重启数据库最容易把在途写入一起带走,除非确认没有写入在途,否则放在最后考虑。 平时建议把慢查询日志常开,long_query_time 保持 1 秒,配合告警每周翻一次日志。数据库这一层的性能问题,索引治理永远排在升配前面。