select * from t_user where phone = 1300000001;
但是如果索引字段是整型类型,查询条件中的输入参数即使字符串,是不会导致索引失效,还是可以走索引扫描 。
我们再看第二个例子,id 是整型,但是下面这条语句还是走了索引扫描的 。
explain select * from t_user where id = '1';
文章插图
为什么第一个例子会导致索引失效,而第二例子不会呢?要明白这个原因,首先我们要知道 MySQL 的数据类型转换规则是什么?就是看 MySQL 是会将字符串转成数字处理,还是将数字转换成字符串处理 。
我在看《mysql45讲的时候》看到一个简单的测试方式,就是通过 select “10” > 9 的结果来知道MySQL 的数据类型转换规则是什么:
- 如果规则是 MySQL 会将自动「字符串」转换成「数字」,就相当于 select 10 > 9,这个就是数字比较,所以结果应该是 1;
- 如果规则是 MySQL 会将自动「数字」转换成「字符串」,就相当于 select "10" > "9",这个是字符串比较,字符串比较大小是逐位从高位到低位逐个比较(按ascii码),那么"10"字符串相当于 “1”和“0”字符的组合,所以先是拿 “1” 字符和 “9” 字符比较,因为 “1” 字符比 “9” 字符小,所以结果应该是 0 。
文章插图
上面的结果为 1,说明 MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较 。
前面的例子一中的查询语句,我也跟大家说了是会走全表扫描:
//例子一的查询语句select * from t_user where phone = 1300000001;
这是因为 phone 字段为字符串,所以 MySQL 要会自动把字符串转为数字,所以这条语句相当于:select * from t_user where CAST(phone AS signed int) = 1300000001;
可以看到,CAST 函数是作用在了 phone 字段,而 phone 字段是索引,也就是对索引使用了函数!而前面我们也说了,对索引使用函数是会导致索引失效的 。例子二中的查询语句,我跟大家说了是会走索引扫描:
//例子二的查询语句select * from t_user where id = "1";
这时因为字符串部分是输入参数,也就需要将字符串转为数字,所以这条语句相当于:select * from t_user where id = CAST("1" AS signed int);
可以看到,索引字段并没有用任何函数,CAST 函数是用在了输入参数,因此是可以走索引扫描的 。联合索引非最左匹配对主键字段建立的索引叫做聚簇索引,对普通字段建立的索引叫做二级索引 。
那么多个普通字段组合在一起创建的索引就叫做联合索引,也叫组合索引 。
创建联合索引时,我们需要注意创建时的顺序问题,因为联合索引 (x, y, z) 和 (z, y, x) 在使用的时候会存在差别 。
联合索引要能正确使用需要遵循最左匹配原则,也就是按照最左优先的方式进行索引的匹配 。
比如,如果创建了一个
(a, b, c)
联合索引,如果查询条件是以下这几种,就可以匹配上联合索引:- where a=1;
- where a=1 and b=2 and c=3;
- where a=1 and b=2;
但是,如果查询条件是以下这几种,因为不符合最左匹配原则,所以就无法匹配上联合索引,联合索引就会失效:
- where b=2;
- where c=3;
- where b=2 and c=3;
经验总结扩展阅读
- MySQL 全局锁、表级锁、行级锁,你搞清楚了吗?
- golang中的nil接收器
- llinux下mysql建库、新建用户、用户授权、修改用户密码
- RedHat7.6安装mysql8步骤
- golang中的字符串
- flutter系列之:flutter中可以建索引的栈布局IndexedStack
- 究极无敌细节版 Mysql索引
- Mysql通过Canal同步Elasticsearch
- MySQL的日志文件
- 01-MySQL8主从详解