数据库索引失效了...

故事背景

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

相关推荐
凤山老林6 小时前
Spring Boot 启动冲刺:耗时剖析、懒加载策略与事件驱动初始化优化
spring boot·后端·python
朱涛的自习室7 小时前
我给 Gemini 4 和 DeepSeek 搞了套「末位淘汰」,AI 干活会更猛吗?(Day 3)
android·前端·后端
woniu_maggie10 小时前
SAP MDG主数据治理实战:从架构原理到项目实施全解析
后端
狗凯之家源码网10 小时前
纯 PHP+MySQL 应用市场系统源码实测!
开发语言·mysql·php
xiaoqiMikko10 小时前
Redis 实战(一):内存满了 —— 拒写、淘汰、被系统杀掉,以及删了 key 内存为什么不降(6.2.4 实测)
redis·后端
工程师小爱10 小时前
电芯尺寸合格,不等于电池包尺寸合格
后端
geovindu10 小时前
rust:Memento Pattern(续)
开发语言·后端·设计模式·rust·行为模式·备忘录模
姚远Oracle ACE10 小时前
对比测试了 openGauss、PostgreSQL、Oracle、MySQL 的CPU 指令数
mysql·postgresql·oracle
闲云lazycloud10 小时前
第 1 课:Harness 与 Agent 运行时
人工智能·后端