Spring JPA MySQL带索引查询千万级表耗时超1秒排查
问题根因
1. 核心原因:隐式类型转换导致索引无法正常生效
你实际触发慢查询的语句和做explain测试的语句参数写法不一致:
- 慢日志记录的实际执行SQL:
select * from temp where cust_id=211313131;,传入的cust_id参数是不带引号的整数值 - 你做explain测试的SQL:
select * from temp where cust_id="31231234343";,传入的是带引号的字符串值
而表结构中cust_id字段定义为varchar(100)字符串类型,当传入整数参数时,MySQL会对表中每一行的cust_id值做隐式类型转换(转为数字后再比对),这种场景下无法利用B+树索引的等值快速匹配能力,虽然执行计划表面显示选中了idx_subscribers_cust_id索引,但实际会扫描索引上的大量数据块,和慢日志中Rows_examined: 3273885(扫描超327万行)的记录完全吻合,自然查询耗时会超过1秒。
2. 次要问题:索引统计信息严重失真
从show index的输出可以看到,3400万行数据的表,idx_subscribers_cust_id索引的Cardinality(索引不重复值统计)仅为281,这个数值和cust_id作为客户ID的实际低重复率特征严重不符。失真的统计信息会让MySQL优化器无法准确判断索引筛选能力,容易触发异常执行计划。
修复方案
- 统一参数类型:不管是直接写SQL还是Spring JPA中传参,保证传入
cust_id的参数类型为字符串,和字段定义一致,杜绝隐式转换。修正后查询的扫描行数会降到个位数,耗时可稳定在毫秒级。 - 更新统计信息:执行
ANALYZE TABLE temp;命令重新收集表和索引的统计数据,给优化器提供准确的判断依据。 - 长期优化:如果业务中cust_id是固定长度的纯数字ID,可以将字段类型调整为
bigint,既从根源避免隐式转换问题,还能缩小索引体积,进一步提升查询效率。
内容的提问来源于stack exchange,提问作者krishna k maurya
相关产品推荐
相关产品推荐

