数据库索引失效了...

故事背景

数据库有一个大表需要添加几个字段,我要先看有没有其他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 跑飞了才动手,那就真的是亡羊补牢了。

相关推荐
风象南34 分钟前
我把大脑开源给了AI
人工智能·后端
橙序员小站5 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
怒放吧德德5 小时前
Netty 4.2 入门指南:从概念到第一个程序
java·后端·netty
雨中飘荡的记忆7 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
开心就好20258 小时前
UniApp开发应用多平台上架全流程:H5小程序iOS和Android
后端·ios
悟空码字8 小时前
告别“屎山代码”:AI 代码整洁器让老项目重获新生
后端·aigc·ai编程
小码哥_常9 小时前
大厂不宠@Transactional,背后藏着啥秘密?
后端
奋斗小强9 小时前
内存危机突围战:从原理辨析到线上实战,彻底搞懂 OOM 与内存泄漏
后端
小码哥_常9 小时前
Spring Boot接口防抖秘籍:告别“手抖”,守护数据一致性
后端
心之语歌9 小时前
基于注解+拦截器的API动态路由实现方案
java·后端