数据库瓶颈分析:慢查询定位与死锁排查
做库存系统,数据库往往是第一个扛不住的。我见过太多系统,业务逻辑写得花里胡哨,结果一到数据库层面就崩了。今天咱们就聊聊,怎么从数据库层面找到性能瓶颈。
慢查询定位:从日志到执行计划
先说慢查询日志。这东西就像飞机的黑匣子,记录着所有"飞得慢"的SQL。我个人习惯,上线前就会把慢查询日志打开,阈值设个1秒。
-- 开启慢查询日志(MySQL)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 超过1秒就算慢
SET GLOBAL log_queries_not_using_indexes = 'ON'; -- 没走索引的也记下来
拿到慢查询日志后,别急着改。先用EXPLAIN看看执行计划。我记得有一次,一个库存扣减接口响应特别慢,日志里看到一条UPDATE语句跑了3秒多。EXPLAIN一看,好家伙,全表扫描。
EXPLAIN SELECT * FROM inventory WHERE product_id = 'P10086' AND warehouse_id = 'WH01';
-- 结果:type=ALL, rows=500000, Extra=Using where
type=ALL就是全表扫描,rows=50万行。这能不慢吗?
EXPLAIN关键字段解读:
| 字段 | 含义 | 好/坏 |
|---|---|---|
| type | 访问类型 | const > eq_ref > ref > range > index > ALL |
| key | 实际使用的索引 | 有值最好,NULL最差 |
| rows | 预估扫描行数 | 越小越好 |
| Extra | 额外信息 | Using filesort、Using temporary 要警惕 |
索引失效场景:我踩过的坑
索引失效,说白了就是建了索引但没用上。我总结了几种常见情况,都是我在项目中真实遇到过的。
- 隐式类型转换:字段是varchar,传参传了数字。MySQL会做类型转换,索引就废了。
- 前模糊匹配:LIKE '%abc',索引没法用。你想想看,索引是按前缀排序的,你从中间开始匹配,它怎么找?
- 函数操作:WHERE DATE(create_time) = '2024-01-01',索引失效。改成范围查询就好。
- OR条件:OR两边只要有一个没索引,整个查询就不走索引。
- 联合索引最左前缀:索引是(a,b,c),你查b和c,跳过了a,索引失效。
避坑指南:我曾经在一个库存查询接口里,用了WHERE status IN (1,2,3) AND product_id LIKE '%P10%'。结果status字段有索引,但product_id用了前模糊,整个查询走了全表扫描。后来改成先查status再在代码里过滤,性能提升了10倍。
死锁排查与预防
死锁是库存系统的高发问题。为什么?因为多个事务同时操作同一批库存记录,互相等待对方释放锁。
先看怎么排查。MySQL提供了几个命令,我一般这么用:
-- 查看当前正在运行的事务
SELECT * FROM information_schema.INNODB_TRX\G
-- 查看锁等待情况
SELECT * FROM information_schema.INNODB_LOCK_WAITS\G
-- 查看最近一次死锁日志
SHOW ENGINE INNODB STATUS\G
死锁日志里会明确告诉你:哪个事务持有哪个锁,哪个事务在等待哪个锁,最后MySQL选择了哪个事务作为"牺牲品"回滚掉。
预防死锁,我有几个建议:
- 统一访问顺序:所有事务都按相同的顺序访问资源。比如先扣主库存,再扣子库存,别反过来。
- 缩短事务时间:事务里别做远程调用、别做复杂计算。拿到锁就赶紧干活,干完就提交。
- 使用低隔离级别:如果业务允许,用READ COMMITTED代替REPEATABLE READ,能减少间隙锁导致的死锁。
- 合理设计索引:索引可以减少锁的粒度。行锁比表锁好,但前提是索引要能命中。
注意:死锁不是bug,是数据库的正常行为。关键在于减少死锁发生的概率,以及做好重试机制。我曾经在库存扣减接口里加了最多3次重试,每次重试前随机等待100-500ms,效果很好。
知识体系:数据库瓶颈分析全景图
下面这张图,是我自己整理的数据库瓶颈分析流程。从发现问题到定位问题,再到解决问题,一条线走下来。
嗯,数据库瓶颈分析,说白了就是三步走:先找到慢的SQL,再用EXPLAIN看它为什么慢,最后对症下药。索引失效和死锁是库存系统里最常见的两个坑,我建议你在开发阶段就把这些检查点加进去,别等到线上出问题了再查。
我的小习惯:每次上线前,我会把慢查询日志阈值调到0.1秒,跑一遍核心接口的自动化测试。这样能提前发现很多索引问题。另外,死锁日志我会定期收集分析,看看有没有规律性的死锁模式,从根源上解决。
公众号:蓝海资料掘金营,微信deep3321