一个字符类型的、一个int类型的,查询的时候到底会不会走索引,其实不少工做了几年的开发人员有时也会晕,下面就用具体事例来测试一下。mysql
先准备2张表,以备后续测试使用。sql
表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,'5','1'),(4,'100','0'),(3,'30','1'),(10,'500','0'),(11,'20','0'),(12,'20a','0'),(15,'020b','1');
两张表的差别是c_no的字段类型不一样。测试
test1.c_no字段为int类型,下面分别用整型和字符串进行比较,查看是否走索引。对应的执行计划以下:spa
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) 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(常量的等值查询),扫行数为1code
也就是说当表中的字段类型为整型时,不管查询用字符串类型的数字仍是int类型的数字均能走索引。其中用int类型的值查询能走索引能够容易理解,那么,字符型的为何能走? 其实这里的字符类型作了隐式转化,上例中就至关于blog
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)
以一样的方式测试一下test2的查询状况索引
先测试正常状况下字符型与字符型比较,结果可想而知,能够走索引,以下:开发
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 | 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以前的版本)。
其实针对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)
经过上面的简单测试,便可发现以下结论:
所以开发同窗在写SQL的时候要注意SQL的写法,缺乏一个单引号可能致使很大的性能差别。