本文目录导读:
- 杀手锏:缩小事务范围(最有效)
- 提速:优化慢查询(锁的源头)
- 减量:减少锁住的数据量
- 改模式:调整事务隔离级别(根据业务选择)
- 调姿势:优化SQL书写顺序
- 加“作弊码”:使用乐观锁(适合读多写少)
- 超时与监控:设置合理的锁等待超时
- 架构层面:读写分离与缓存
- 快速诊断与行动清单
锁等待(Lock Wait)是数据库并发控制中的常见问题,优化锁等待的核心思路是:减少锁的持有时间 和 降低锁的竞争粒度。
以下是具体的优化策略,按优先级排列:
杀手锏:缩小事务范围(最有效)
锁是在事务提交或回滚时才释放的,事务越长,锁持有时间越长,冲突概率越高。
- 坏例子:在一个事务里先查数据,然后调用远程API(耗时3秒),再更新数据,这3秒内锁一直被持有。
- 好做法:只将
UPDATE/DELETE/INSERT等真正需要锁的操作放入事务,将耗时的业务逻辑(如网络请求、复杂计算)放在事务之外。 - 原则:事务中只做必须的数据库操作,不做“思考”和“等待”。
提速:优化慢查询(锁的源头)
锁的持有时间 = 查询执行时间,查询越慢,锁被持有越久。
- 加索引:检查
WHERE条件、JOIN和ORDER BY涉及的列是否缺少索引,缺少索引会导致全表扫描,锁住大量不必要的数据(甚至整张表)。 - 避免在UPDATE的WHERE条件上使用函数:如
WHERE DATE(create_time)=...会导致索引失效,产生表锁。 - 使用EXPLAIN分析:确保执行计划是
Using Index或ref类型,避免Using temporary(文件排序)或Using filesort。
减量:减少锁住的数据量
- 精准定位:
UPDATE时WHERE条件要精准,尽量用唯一索引或主键(行锁),避免一次锁住多行。 - 分批操作:如果需要批量更新大量数据(如几百万行),不要在一个事务里全量更新,拆分成每1000行一个事务,中间留
SLEEP(0.1)秒让其他事务获得执行机会。- 示例: 循环
UPDATE table SET status=1 WHERE id BETWEEN 1 AND 1000; COMMIT;接着处理1001-2000。
- 示例: 循环
改模式:调整事务隔离级别(根据业务选择)
隔离级别越高,锁机制越严格,等待越多。
- READ COMMITTED(RC):多数情况下,从
REPEATABLE READ(RR)降级到RC能显著减少锁等待,因为RC级别不会产生“间隙锁”,只锁住行本身,极大降低了“幻读”导致的锁冲突概率。 - 注意事项:业务是否能容忍不可重复读?大部分OLTP(在线事务处理)场景是可以的。
调姿势:优化SQL书写顺序
- 在事务中,按相同顺序访问资源:所有更新用户A和用户B的事务,都先锁A,再锁B,这样可以避免“死锁”(Deadlock),死锁会导致其中一个事务回滚重试,浪费更多时间。
- 避免热点行更新:例如对“余额表”中的某一行频繁更新,可考虑分桶(将一行拆成10个逻辑子账户),随机选择一个子账户更新,分散热点。
加“作弊码”:使用乐观锁(适合读多写少)
如果冲突概率不高(比如5%以下),可用乐观锁代替行锁,完全避免锁等待。
- 原理:在数据表中加一个
version字段。UPDATE table SET count=count+1, version=version+1 WHERE id=X AND version=old_version; - 优点:没有锁,更新失败(返回影响行数为0)时只需重试即可。
- 缺点:高并发下大量重试反而降低性能。
超时与监控:设置合理的锁等待超时
- 设置较短超时:在数据库或连接层设置
lock_wait_timeout(MySQL默认50秒,可调至5-10秒),避免应用无限期卡住。 - 监控锁等待:使用命令(如
SHOW PROCESSLIST中的Waiting for table metadata lock、查询performance_schema或sys.innodb_lock_waits)识别并紧急终止阻塞源头的事务(KILL连接)。
架构层面:读写分离与缓存
- 读写分离:将
SELECT(特别是长查询)路由到备库,避免占用主库的写锁或读锁(RR级别下读也加锁)。 - 缓存:把高频读取但不常变动的数据(如配置、商品名称)放入Redis或本地缓存,减少数据库查询压力,进而减少锁冲突。
快速诊断与行动清单
- 先看:是不是长事务在作祟?
SELECT * FROM information_schema.INNODB_TRX\G找到运行时间最长的事务,想办法拆短它。 - 再看:是不是没有索引导致锁了整张表?用
EXPLAIN分析慢SQL。 - 最后:如果上面都正常,考虑降级隔离级别 或 改用乐观锁。
一句话口诀:短事务、快SQL、准条件、少行锁、分批改、降隔离。