Mysql下的SQL优化——隐式类型转换

本文通过一次实际的索引查询实验,揭示了在MySQL中,字段类型与查询条件类型的匹配对于索引使用的至关重要性。当两者类型不一致时,可能会触发隐式类型转换,从而导致索引失效。

前几天同事问了一个问题:在一个只有两个值的字段上加索引,在以这个字段为查询条件的时候是否会走索引。同事说不会,我说会走索引。同事不服,于是我们当场做了一个实验。结果居然没有走索引,满脸尴尬,难道真的是我错了?接下来我们分析下

实验表的情况如下

表结构

FieldTypeNullKey
idint(11)NOPRI
ssssvarchar(20)YES
sextinyint(1)YESMUL
varvarchar(1) YESMUL
aaavarchar(1)YES
cccvarchar(1)YES
eeevarchar(1)YES
dddvarchar(1)YES

总数据量200W

数据分布

var的值数据量
09
12097143

var字段只有两种值:0和1。0有9条,1有200W+条

索引

索引名字段索引类型索引方法
idx_varvarNormalBTREE

查询语句

select * from test_200 where var = 1;

执行计划

select typetabletypepossible keyskeykey lenrefrowsfilteredextra
SIMPLEtest_200ALLidx_var202824610Using where

执行计划中显示没有走索引,而是全表扫描,这是为什么呢?

EXPLAIN EXTENDED 看下:

EXPLAIN EXTENDED select * from test_200 where var = 1;
show warnings;
levelCodemessage
Warning1681‘EXTENDED’ is deprecated and will be removed in a future release.
Warning1739Cannot use ref access on index ‘idx_var’
due to type or collation conversion on field ‘var’
Warning1739Cannot use range access on index ‘idx_var’
due to type or collation conversion on field ‘var’
Note1003/* select#1 */ select test.test_200.id AS id,
test.test_200.ssss AS ssss,
test.test_200.sex AS sex,
test.test_200.var AS var,
test.test_200.aaa AS aaa,
test.test_200.ccc AS ccc,
test.test_200.eee AS eee,
test.test_200.ddd AS ddd from test.test_200
where (test.test_200.var = 1)

看到警告中的提示,我开始有点想法了。
提示中说

Cannot use ref access on index ‘idx_var’ due to type or collation conversion on field ‘var’
Cannot use range access on index ‘idx_var’ due to type or collation conversion on field ‘var’

简单来说就是:本次查询不能走 idx_var 这个索引,因为在var 这个字段上发生了类型转换

var 是varchar类型, where条件中使用的是却是数字型 “where var = 1”。所以mysql为了方便与where条件中的1进行比较,把全表中的var值都转换成了数字型,导致了全表扫描。

好了,接下来验证一下我的想法:

查询语句 :

select * from test_200 where var = '1';

执行计划

select typetabletypepossible keyskeykey lenrefrowsfilteredextra
SIMPLEtest_200refidx_varidx_var6const1014123100

从执行计划可以看出,查询已经走索引了。之前不走索引,并不是因为这个字段只有两种值,而是因为where条件的类型不正确,导致mysql进行了 隐式类型转换


  • 隐式类型转换

什么是mysql的隐式类型转换?

看下官网的描述 隐式类型转换

### MySQL 字符串隐式类型转换规则 在 MySQL 中,当操作涉及不同类型的值时会发生隐式类型转换。对于字符串到其他类型的转换有特定的行为模式。 #### 转换为数值型 当一个字符串被用于算术运算或与数值进行比较时,MySQL 尝试将其解析成浮点数或整数[^1]。例如: ```sql SELECT '123' + 456; -- 结果为 579, 因为 '123' 被解释成了数字 123. ``` 如果字符串开头部分可以成功转化为有效的数字,则只取这部分作为结果;其余非数字字符会被忽略掉。但如果整个字符串都不能表示任何有效数字,则返回0[^4]。 #### 转换为日期时间型 某些情况下,MySQL 可能会尝试把看起来像日期/时间格式的字符串转成相应的 DATE 或 DATETIME 类型。比如: ```sql SELECT STR_TO_DATE('2023-08-15','%Y-%m-%d'); -- 成功转换并返回对应日期对象 ``` 不过需要注意的是,并不是所有的看似合理的日期字符串都能顺利完成这样的转变——这取决于具体上下文中所期望的目标类型以及所提供的格式化模板是否匹配实际输入的内容。 #### 应用场景及注意事项 尽管这些功能提供了灵活性,但在实践中应当谨慎对待它们带来的便利性。因为依赖于隐式转换可能导致意外行为的发生,尤其是在涉及到索引优化方面可能会造成负面影响[^5]。因此建议尽可能地保持数据的一致性和明确性,在必要之处采用显示强制转换函数(如 CAST() 和 CONVERT()),从而确保预期之外的情况不会影响应用程序逻辑正确性的实现。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值