1. mysql> CREATE TABLE `tradelog` (
  2. `id` int(11) NOT NULL,
  3. `tradeid` varchar(32) DEFAULT NULL,
  4. `operator` int(11) DEFAULT NULL,
  5. `t_modified` datetime DEFAULT NULL,
  6. PRIMARY KEY (`id`),
  7. KEY `tradeid` (`tradeid`),
  8. KEY `t_modified` (`t_modified`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

1、使用函数

2、隐式类型转换

select * from tradelog where tradeid=123123;

如果字段类型与传入的值的类型不一致,就会发生类型转换,上边的sql,tradeid为varchar,而传入的为整型,所以需要进行类型转换。

转换的规则

看 select ‘10’ > 9的结果

  • 如果结果为 1 ,那么就说明是字符串转成了整型
  • 如果结果为0,那么就说明是整型转换成了字符型

image.png
说明为字符型转换为了整型,那么针对上边的SQL就是,字段的值做了类型转换,就相当于

mysql> select * from tradelog where  CAST(tradid AS signed int) = 123123;

使用了函数,因此不走索引.
如果tradid字段是int,而sql是trandid = ‘1231312’,那么会走索引吗,答案是类型发生了转换,但是是传入的值的类型发生了转换,从字符型转换为int,字段并没有使用函数,因此还是会走索引

3、隐式字符编码转换

再创建一张关联表

mysql> CREATE TABLE `trade_detail` (
  `id` int(11) NOT NULL,
  `tradeid` varchar(32) DEFAULT NULL,
  `trade_step` int(11) DEFAULT NULL, /*操作步骤*/
  `step_info` varchar(32) DEFAULT NULL, /*步骤信息*/
  PRIMARY KEY (`id`),
  KEY `tradeid` (`tradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

两个表的字符集分别是utf8mb4和utf8;
utf8mb4是utf8的超集,当这两个类型的字符串在作比较的时候, MySQL内部是先吧utf8字符串转换成utf8mb4字符集再作比较。
如果要查询tradelog表的id=2的tradeid的所有操作步骤,sql要这么写

mysql> select d.* from tradelog l, trade_detail d where d.tradeid=l.tradeid and l.id=2; /*语句Q1*/

索引失效的情况 - 图2
查询表tradelog是使用了索引的,但是查询detail没有使用索引,为什么?
因为tradelog的tradeid字段为utfmb4,执行d.tradeid=l.tradeid的时候,内部d.tradeid相当于执行了CONVERT(traideid USING utf8mb4),字段使用了函数,因此不走索引。

解决方法

1、可以将传入的值的字符类型进行转换,转换成和字段类型一致的,就会重新使用索引
2、可以将两张表的字符集改为一致的