varchar int 查询 到底什么情况下走索引?
一个字符类型的、一个int类型的,查询的时候到底会不会走索引,其实很多工作了几年的开发人员有时也会晕,下面就用具体事例来测试一下。
1. 准备工作
先准备2张表,以备后续测试使用。
表1:创建表test1,总共3列,其中id 是主键(int),c_no 为int型,且有索引,c_2为普通字段
/*创建表test1 */
create table test1(id int primary key,c_no int ,c_2 varchar(1),key c_no(c_no)); /* 插入一些测试数据 */
insert into test1 values(1,1,'0'),(2,2,'1'),(3,4,'1'),(4,6,'0'),(5,7,''1),(6,11,'2'),(7,5,'3'),(8,100,'0'),(9,30,'1'),(10,50,'0');
表2: 创建表test1,总共3列,其中id 是主键(int),c_no 为字符型,且有索引,c_2为普通字段
/* 创建test2 */
create table test2(id int primary key auto_increment,c_no varchar(11) ,c2 varchar(2),key c_no(c_no)); /* 插入一些测试数据 */
insert into test2 values(1,'',''),(4,'',''),(3,'',''),(10,'',''),(11,'',''),(12,'20a',''),(15,'020b','');
两张表的差异是c_no的字段类型不同。
2. 等值查询测试
2.1 测试test1
test1.c_no字段为int类型,下面分别用整型和字符串进行比较,查看是否走索引。对应的执行计划如下:
mysql> explain select * from test1 where c_no='';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | test1 | NULL | ref | c_no | c_no | 5 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec) mysql> explain select * from test1 where c_no=100;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | test1 | NULL | ref | c_no | c_no | 5 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
可见,两种方式均走索引了,且走的是c_no的索引,类型为ref为const(常量的等值查询),扫行数为1
也就是说当表中的字段类型为整型时,无论查询用字符串类型的数字还是int类型的数字均能走索引。其中用int类型的值查询能走索引可以容易理解,那么,字符型的为什么能走? 其实这里的字符类型做了隐式转化,上例中就相当于
mysql> explain  select *  from test1 where c_no=CAST('100' as UNSIGNED);
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test1 | NULL       | ref  | c_no          | c_no | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
2.2 测试 test2 表
以同样的方式测试一下test2的查询情况
先测试正常情况下字符型与字符型比较,结果可想而知,可以走索引,如下:
mysql> explain select * from test2 where c_no='';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | test2 | NULL | ref | c_no | c_no | 47 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
而,如果是整型再查呢?结果如下(很遗憾,不能走索引了)
mysql> explain select * from test2 where c_no=100;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | test2 | NULL | ALL | c_no | NULL | NULL | NULL | 7 | 14.29 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 3 warnings (0.00 sec)
也就是说,表中字段为字符类型的时候,查询的值为整型时,无法走索引了。
那这句相当于如下情况:
mysql> explain select * from test2 where cast(c_no as unsigned)=100;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | test2 | NULL | ALL | NULL | NULL | NULL | NULL | 7 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
也就是c_no做了隐式转化。因为如果是100做了影视转化,那么结果应该是可以走索引,例如:
mysql> explain select * from test2 where c_no=cast(100 as char);
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | test2 | NULL | ref | c_no | c_no | 47 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
由此,我们也应证了如果字段做了函数计算后,该列上即使有索引也无法使用(MySQL8.0之前的版本)。
2.3 进一步测试
其实针对test2表 还可以测试一点,进一步证明是c_no字段做了隐式转化,例如:
mysql> select * from test2 where c_no=20;
+----+------+------+
| id | c_no | c2 |
+----+------+------+
| 11 | 20 | 0 |
| 12 | 20a | 0 |
| 15 | 020b | 1 |
+----+------+------+
3 rows in set, 2 warnings (0.00 sec)
另外,看到了2个警告,内容如下:
mysql> show warnings;
+---------+------+------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '20a' |
| Warning | 1292 | Truncated incorrect DOUBLE value: '020b' |
+---------+------+------------------------------------------+
2 rows in set (0.00 sec)
更加证明了转化为数字型(预转为double)
3. 小结
通过上面的简单测试,即可发现如下结论:
- 当表中的字段类型为整型时,无论查询用字符串类型的数字还是int类型的数字均能走索引;
 - 表中字段为字符类型的时候,查询的值为整型时,无法走索引;
 - 如果字段做了函数计算后,该列上即使有索引也无法使用(MySQL8.0之前的版本)
 
因此开发同学在写SQL的时候要注意SQL的写法,缺少一个单引号可能导致很大的性能差异。
varchar int 查询 到底什么情况下走索引?的更多相关文章
- 数据库表设计时一对一关系存在的必要性    数据库一对一、一对多、多对多设计  面试逻辑题3.31  sql server 查询某个表被哪些存储过程调用  DataTable根据字段去重  .Net Core Cors中间件解析  分析MySQL中哪些情况下数据库索引会失效
		
数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...
 - oracle数据库什么情况下创建索引比较好
		
索引就好象一本字典的目录.凭借字典的目录,我们可以非常迅速的找到我们所需要的条目.数据库也是如此.凭借Oracle数据库的索引,相关语句可以迅速的定位记录的位置,而不必去定位整个表. 虽 然说,在表中 ...
 - vue-router两种模式,到底什么情况下用hash,什么情况下用history模式呢?
		
转:https://segmentfault.com/q/1010000010340823/a-1020000010598395 为什么要有 hash 和 history 对于 Vue 这类渐进式前端 ...
 - 分析MySQL中哪些情况下数据库索引会失效
		
要想分析MySQL查询语句中的相关信息,如是全表查询还是部分查询,就要用到explain. 一.explain 用法:explain +查询语句. id:查询语句的序列号,上面图片中只有一个selec ...
 - mysql什么情况下使用索引
		
表的主关键字 自动建立唯一索引 如zl_yhjbqk(用户基本情况)中的hbs_bh(户标识编号) 表的字段唯一约束 ORACLE利用索引来保证数据的完整性 如lc_hj(流程环节)中的lc_bh+h ...
 - MongoDB之几种情况下的索引选择策略
		
一.MongoDB如何选择索引 如果我们在Collection建了5个index,那么当我们查询的时候,MongoDB会根据查询语句的筛选条件.sort排序等来定位可以使用的index作为候选索引:然 ...
 - 【MySQL 原理分析】之 Explain & Trace 深入分析全模糊查询走索引的原理
		
一.背景 今天,交流群有一位同学提出了一个问题.看下图: 之后,这位同学确实也发了一个全模糊查询走索引的例子: 到这我们可以发现,这两个sql最大的区别是:一个是查询全字段(select *),而一个 ...
 - MYSQL 索引类型、什么情况下用不上索引、什么情况下不推荐使用索引
		
mysql explain的使用: http://blog.csdn.net/kaka1121/article/details/53394426 索引类型 在数据库表中,对字段建立索引可以大大提高查询 ...
 - 关于MySQL什么时候使用索引问题以及什么情况下应不建或少建索引
		
一,什么情况下使用索引1. 表的主关键字 自动建立唯一索引 2. 表的字段唯一约束 ORACLE利用索引来保证数据的完整性 3. 直接条件查询的字段 在SQL中用于条件约束的字段 如zl_yhjbqk ...
 
随机推荐
- 对话|首席研究员童欣:从长远看,AR的应用范围远比VR广泛
			
童欣博士现任微软亚洲研究院网络图形组首席研究员.1993年毕业于浙江大学计算机系,获工学学士学位:1996年获浙江大学计算机系硕士学位:1999年获清华大学计算机系博士学位,同年加入微软亚洲研究院. ...
 - 渗透之——MSF提权
			
在WEB渗透中当我们拿到webshell了,我们可以试试用MSF(metasploit)来进行提权,在MSF里meterpreter很强大的! 我们先用msfvenom生成一个EXE的木马后门. ms ...
 - SQL语句中in 与 exists的区别
			
SQL语句中in 与 exists的区别 SQL中EXISTS检查是否有结果,判断是否有记录,返回的是一个布尔型(true/false); IN是对结果值进行比较,判断一个字段是否存在于几个值的范围中 ...
 - JZOJ 5235. 【NOIP2017模拟8.7A组】好的排列
			
5235. [NOIP2017模拟8.7A组]好的排列 (File IO): input:permutation.in output:permutation.out Time Limits: 1000 ...
 - PAT-字符串处理-B1006 换个格式输出整数 (15分)
			
题目描述: 让我们用字母 B 来表示“百”.字母 S 表示“十”,用 12...n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超过 3 位的正整数.例如 234 应该被输出为 ...
 - 超级干货:动态防御WAF技术原理及编程实战!
			
本文带给大家的内容是动态防御WAF的技术原理及编程实战. 将通过介绍ShareWAF的核心技术点,向大家展示动态防御的优势.实现思路,并以编程实战的方式向大家展示如何在WAF产品开发过程中应用动态防御 ...
 - Mysql(Mariadb)慢查询日志中long_query_time 与log_queries_not_using_indexes与min_examined_row_limit 关系分析
			
慢查询日志中long_query_time 与log_queries_not_using_indexes与min_examined_row_limit 关系分析 参数介绍: long_query_ ...
 - 《即时消息技术剖析与实战》学习笔记12——IM系统如何提升图片、音视频消息发送、浏览的体验
			
IM系统如何提升用户发送.浏览图片和音视频消息的体验呢?一是保证图片.音视频消息发送得又快又稳,二是保证用户浏览播放图片.音视频消息时流畅不卡顿. 一.提升用户发送图片.音视频的体验 1. 多上传接入 ...
 - go学习第四天、条件和循环
			
循环 Go语言仅支持循环关键字 for for i := 0; i<5; i++ 示例 while 条件循环 while(n<5) n := 0 for n < 5 { n++ fm ...
 - 通过CGAL将一个多边形剖分成Delaunay三角网
			
目录 1. 概述 2. 实现 3. 结果 4. 参考 1. 概述 对于平面上的点集,通过Delaunay三角剖分算法能够构建一个具有空圆特性和最大化最小角特性的三角网.空圆特性其实就是对于两个共边的三 ...