SQL 生产环境中导致锁等待 / 死锁 / 超时 / OOM 的 Top 15 写法错误
发布时间 - 2026-01-27 00:00:00 点击率:次SQL性能事故主因是15类高危写法,如WHERE未走索引(含隐式类型转换)、函数包裹字段、OFFSET深分页等,修复后QPS稳定、P99延迟降30%~90%。
绝大多数生产 SQL 性能事故,不是因为数据量突增或硬件故障,而是几行看似无害的写法在高并发下被放大成锁、死锁、超时甚至 OOM。下面这 15 类写法,在真实线上环境反复复现过,且修复后 QPS 稳定、P99 延迟下降 30%~90%。
WHERE 条件未走索引(含隐式类型转换)
MySQL / PostgreSQL 中,user_id = '123'(字段是 BIGINT)会触发全表扫描 + 隐式转换,导致该行锁升级为表级锁等待;SQL Server 的 WHERE name = 123(name 是 VARCHAR)同样失效索引。这类语句在压测时可能不显眼,但上线后一并发就卡住。
- 检查执行计划:MySQL 用
EXPLAIN FORMAT=JSON,确认key和rows字段是否合理 - 禁止字符串和数字混用:
id = '1'→ 改为id = 1 - 函数包裹字段:如
WHERE DATE(created_at) =→ 改为
'2025-01-01'
WHERE created_at >= '2025-01-01' AND created_at
UPDATE / DELETE 无 LIMIT 或无主键条件
在 MySQL 中,UPDATE orders SET status = 'done' WHERE user_id = 123 若 user_id 无索引,会锁全表;即使有索引,若匹配行数达数万,也会持锁时间过长,阻塞后续事务。PostgreSQL 虽无“锁表”概念,但大范围 UPDATE 会显著延长 tuple 锁持有时间,引发等待链。
- 所有线上
UPDATE/DELETE必须带LIMIT(如分批处理)或确保 WHERE 含唯一/主键字段 - 批量更新优先用
IN (id1, id2, ...)替代模糊条件,单次不超过 500 行 - 避免
WHERE status != 'done'这类无法利用索引的谓词
SELECT ... FOR UPDATE / LOCK IN SHARE MODE 在非事务块中执行
Spring Boot 默认 @Transactional 传播行为是 REQUIRED,但若开发者在非事务方法里直接调用 JdbcTemplate.queryForObject("SELECT ... FOR UPDATE", ...),MySQL 会自动开启隐式事务,且不自动提交——锁持续到连接关闭或超时(默认 8 小时),极易堆积成锁等待雪崩。
- 强制所有
FOR UPDATE语句包裹在显式事务中,且事务粒度尽量短 - 禁止在 MyBatis 的
@Select注解中写FOR UPDATE,改用@Update+ 显式事务控制 - PostgreSQL 中对应的是
SELECT ... FOR UPDATE NOWAIT,必须加NOWAIT并捕获SQLState 55P03异常
大字段(TEXT / BLOB)参与 SELECT * 或 ORDER BY
MySQL 的 innodb_buffer_pool_size 默认只缓存索引和热数据页,一旦 SELECT * 返回含 content TEXT 的百万行,会迅速耗尽内存,触发大量磁盘 I/O,最终导致连接池打满、OOM Killer 杀进程。ORDER BY 时若用到了未索引的大字段,还会触发 Using filesort + 临时磁盘表(tmp_table_size 不够时)。
- 永远用明确列名代替
*,尤其避开TEXT/BLOB字段 -
ORDER BY只允许出现在已建索引的字段上;若必须按大字段排序,提前生成摘要字段(如content_md5)并建索引 - 应用层做分页时,禁用
OFFSET大值(如OFFSET 100000),改用游标分页(WHERE id > last_id LIMIT 50)
真正难排查的不是慢 SQL,而是“看起来快、并发一上来就崩”的 SQL。比如一个 UPDATE 平均 20ms,但锁持有时间取决于扫描行数而非执行时间;又比如一个 SELECT FOR UPDATE 在单线程下秒返回,但 50 并发时锁等待队列指数增长——这些细节,往往藏在执行计划的 Extra 列和 INFORMATION_SCHEMA.INNODB_TRX 的 TRX_ROWS_LOCKED 里。
# mysql
# js
# json
# ai
# 隐式类型转换
# 隐式转换
# red
# sql
# spring
# spring boot
# mybatis
# for
# select
# date
# format
# 字符串
# 堆
# using
# 线程
# delete
# 类型转换
# 并发
# postgresql
# 分页
# 隐式
# 这类
# 线上
# 死锁
# 的是
# 主键
# 行数
# 大成
# 也会
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在阿里云高效完成企业建站全流程?
Laravel如何实现多对多模型关联?(Eloquent教程)
如何在不使用负向后查找的情况下匹配特定条件前的换行符
如何在阿里云购买域名并搭建网站?
Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?
如何在建站宝盒中设置产品搜索功能?
Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】
标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
js代码实现下拉菜单【推荐】
JS实现鼠标移上去显示图片或微信二维码
西安专业网站制作公司有哪些,陕西省建行官方网站?
html文件怎么打开证书错误_https协议的html打开提示不安全【指南】
C++用Dijkstra(迪杰斯特拉)算法求最短路径
韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南
Laravel怎么创建控制器Controller_Laravel路由绑定与控制器逻辑编写【指南】
Swift中switch语句区间和元组模式匹配
Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用
如何在局域网内绑定自建网站域名?
Laravel Debugbar怎么安装_Laravel调试工具栏配置指南
高防服务器:AI智能防御DDoS攻击与数据安全保障
Linux系统命令中tree命令详解
如何登录建站主机?访问步骤全解析
Laravel表单请求验证类怎么用_Laravel Form Request分离验证逻辑教程
消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工
如何撰写建站申请书?关键要点有哪些?
高端建站如何打造兼具美学与转化的品牌官网?
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
如何在Tomcat中配置并部署网站项目?
JavaScript如何实现类型判断_typeof和instanceof有什么区别
在线制作视频的网站有哪些,电脑如何制作视频短片?
详解vue.js组件化开发实践
百度输入法ai面板怎么关 百度输入法ai面板隐藏技巧
Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】
laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法
百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭
,在苏州找工作,上哪个网站比较好?
Laravel事件监听器怎么写_Laravel Event和Listener使用教程
Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】
高防服务器如何保障网站安全无虞?
Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】
如何在橙子建站中快速调整背景颜色?
如何在Ubuntu系统下快速搭建WordPress个人网站?
如何用已有域名快速搭建网站?
如何在云主机快速搭建网站站点?
Laravel如何使用Scope本地作用域_Laravel模型常用查询逻辑封装技巧【手册】
Bootstrap整体框架之CSS12栅格系统


