数据库索引失效了...

故事背景

数据库有一个大表需要添加几个字段,我要先看有没有其他sql对这个表做操作。

SELECT * FROM information_schema.processlist WHERE command != 'Sleep';

然后发现有一个更新的SQL语句跑了几个小时,用explain语句发现对这个大表做了全表扫描...

sql 复制代码
explain update order_info oi
    INNER JOIN pay_plat pp on oi.mch_order = pp.merchant_order_id
    set oi.product_name = pp.product_name,oi.merchant_data_package = pp.merchant_data_package
		
    where oi.create_time between '2024-09-09' and '2024-09-10'

问题排查

首先我是觉得可能是SQL写错了,但是换了几个SQL的写法都好像不行,就很神奇。

1、不用inner join,直接关联(其实是一样的)

sql 复制代码
explain
 select oi.mch_order,pp.product_name,pp.merchant_data_package 
from order_info oi,pay_plat pp 
where oi.create_time between '2024-09-09' and '2024-09-10'
 and oi.mch_order = pp.merchant_order_id

2、使用子查询

sql 复制代码
explain update ( select * from order_info   where create_time between '2024-09-09' and '2024-09-10') oi
    INNER JOIN pay_plat pp on oi.mch_order = pp.merchant_order_id
    set oi.product_name = pp.product_name,oi.merchant_data_package = pp.merchant_data_package
	

这样写好像也是不行的,子查询不能当做update表 报错:The target table order_info of the UPDATE is not updatable

问了一下gpt,他给我几个优化建议:

1、将日期范围查询改为精确查询(不符合需求)

2、使用强制索引(不行)

3、确保索引覆盖查询(已经确认过字段上都有索引)

4、使用子查询(试过不行)

后面看了一下两个表的编码格式不一样,一个是utf8,一个是utf8mb4,难道就是这个原因?后面改了一下表结构,都改成mb4,explain一下还是不行。然后看了下字段还是utf8,把字段改成utf8mb4要执行很长时间,现在7000万数据执行了半个多小时都还没执行完毕......执行完之后再explain一下看看行不行,估计就是这个问题了。查询这个DDL语句,copy to tmp table这个状态是搞了个临时表。

字段修改完成之后,再查一下发现是走了索引了,大家一定要注意字段编码类型的问题~

索引失效场景

最后再复习一下索引失效场景:

1、like模糊查询

如果使用 LIKE 且通配符 % 在查询条件的开头,索引将失效。最近发现时间用like查一天的天数也会不走索引,比如create_time like '2024-09-10%'。用create_time between '2024-09-10' and '2024-09-11' 这样就可以走索引。

2、索引列有函数或者有计算

3、联合索引最左定则

4、索引列类型不一样,比如id = '字符串',或者编码格式不一样?

5、使用or

6、字段隐式转换

7、使用 !=,not in

等等

最简单还是用explain语句查看sql语句是否走索引,不走的话再一一排查。

总结

大表查询时一定要注意索引是否真正生效,别被"数据量小的时候还能跑得动"给骗了。很多 SQL 在数据量小的时候看不出问题,但一旦数据上来了,没有合适的索引或者写法不合理,性能就会成倍、甚至成指数级地下滑。

我这边遇到的情况是这样的:一年前写的一个 SQL 查询,当时跑一次大概需要 4 分钟,虽然有点慢,但还能接受。结果最近再跑同一个 SQL,发现居然要跑整整 4 个小时!一查才发现,原来某个 join 没有走索引,加上表又变大了,造成了巨大的笛卡尔积,中间还拼命扫全表。

后来花时间重新分析执行计划,调整了索引、改了连接方式,优化之后再跑这条 SQL------只用了 7 秒!从 4 小时到 7 秒,性能直接提升了近 2000 倍

总结几点教训:

  • 联表查询务必确认 join 条件合理,防止隐式笛卡尔积;
  • 索引不是建了就一定能用上,要结合执行计划看是否生效;
  • 不要等系统变慢了才去优化,SQL 写好之后就应该考虑未来扩展;
  • 定期 review 关键 SQL,尤其是跑在大表、大数据量上的。

性能优化真的是"早改早轻松",等 SQL 跑飞了才动手,那就真的是亡羊补牢了。

相关推荐
程序员码歌15 分钟前
【零代码AI编程实战】AI灯塔导航-总结篇
android·前端·后端
java坤坤1 小时前
GoLand 项目从 0 到 1:第八天 ——GORM 命名策略陷阱与 Go 项目启动慢问题攻坚
开发语言·后端·golang
元清加油1 小时前
【Golang】:函数和包
服务器·开发语言·网络·后端·网络协议·golang
bobz9652 小时前
GPT-4.1 对比 GPT-4o
后端
妖灵翎幺2 小时前
Java应届生求职八股(2)---Mysql篇
数据库·mysql
HMBBLOVEPDX2 小时前
MySQL的事务日志:
数据库·mysql
Java小白程序员2 小时前
Spring Framework :IoC 容器的原理与实践
java·后端·spring
小小愿望2 小时前
前端无法获取响应头(如 Content-Disposition)的原因与解决方案
前端·后端
追逐时光者3 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 50 期(2025年8.11-8.17)
后端·.net
杨DaB4 小时前
【SpringBoot】Swagger 接口工具
java·spring boot·后端·restful·swagger