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如何处理和验证JSON类型的数据库字段
高配服务器限时抢购:企业级配置与回收服务一站式优惠方案
魔方云NAT建站如何实现端口转发?
Laravel怎么清理缓存_Laravel optimize clear命令详解
魔毅自助建站系统:模板定制与SEO优化一键生成指南
矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?
如何确保FTP站点访问权限与数据传输安全?
打开php文件提示内存不足_怎么调整php内存限制【解决方案】
WEB开发之注册页面验证码倒计时代码的实现
昵图网官网入口 昵图网素材平台官方入口
如何在新浪SAE免费搭建个人博客?
大型企业网站制作流程,做网站需要注册公司吗?
如何在IIS7上新建站点并设置安全权限?
Android滚轮选择时间控件使用详解
Laravel如何使用Sanctum进行API认证?(SPA实战)
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?
零基础网站服务器架设实战:轻量应用与域名解析配置指南
Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】
Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】
高防服务器租用首荐平台,企业级优惠套餐快速部署
焦点电影公司作品,电影焦点结局是什么?
Mybatis 中的insertOrUpdate操作
通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】
Laravel Fortify是什么,和Jetstream有什么关系
如何快速使用云服务器搭建个人网站?
制作公司内部网站有哪些,内网如何建网站?
Laravel中的withCount方法怎么高效统计关联模型数量
Laravel路由怎么定义_Laravel核心路由系统完全入门指南
香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南
高防服务器如何保障网站安全无虞?
活动邀请函制作网站有哪些,活动邀请函文案?
如何快速配置高效服务器建站软件?
如何在局域网内绑定自建网站域名?
php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
如何在建站之星绑定自定义域名?
java中使用zxing批量生成二维码立牌
Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置
Laravel如何配置和使用缓存?(Redis代码示例)
Internet Explorer官网直接进入 IE浏览器在线体验版网址
大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?
如何彻底删除建站之星生成的Banner?
如何快速建站并高效导出源代码?
大连网站制作公司哪家好一点,大连买房网站哪个好?
,交易猫的商品怎么发布到网站上去?
IOS倒计时设置UIButton标题title的抖动问题
,怎么在广州志愿者网站注册?
Swift中swift中的switch 语句
详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)


