大家都知道,如果联表查询中,数据类型不一样,是很有可能不走索引的,但是有时候数据类型一样也是有可能不走索引的,我们往下看
1 数据准备
我们准备两个表,用来模拟联表查询
1.1 user表
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号码',
PRIMARY KEY (`id`) USING BTREE,
KEY `index_phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `user` (`id`, `phone`) VALUES (1, '13836038931');
INSERT INTO `user` (`id`, `phone`) VALUES (2, '13836038932');
1.2 user_info表
CREATE TABLE `user_info` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`phone` varchar(50) CHARACTER SET utf8 NOT NULL,
`sex` int(11) NOT NULL COMMENT '性别(0:女,1:男)',
`intro` text NOT NULL COMMENT '简介',
PRIMARY KEY (`id`),
KEY `index_phone` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;
INSERT INTO `user_info` (`id`, `phone`, `sex`, `intro`) VALUES (1, '13836038931', 1, '简介');
INSERT INTO `user_info` (`id`, `phone`, `sex`, `intro`) VALUES (2, '13836038932', 0, '简介');
INSERT INTO `user_info` (`id`, `phone`, `sex`, `intro`) VALUES (3, '110', 1, '警察');
INSERT INTO `user_info` (`id`, `phone`, `sex`, `intro`) VALUES (4, '120', 1, '消防员');
INSERT INTO `user_info` (`id`, `phone`, `sex`, `intro`) VALUES (5, '119', 1, '医生');
2 情景再现
请看上述两个表的表结构,两个表的phone字段的字段类型都是varchar(50),但是字符集是不一样的,一个是utf8mb4,一个是utf8,所以我们执行一下SQL:
select u.phone, ui.sex, ui.intro
from user u
inner join user_info ui on u.phone = ui.phone;
执行结果:
执行结果没问题,我们看下是否走了索引
由此可见索引没走了,走全表了,造成这种情况无外乎两种原因:
第一种sql数据太少,sql优化器认为走全表更快,不走索引
第二种就是两个字段虽然数据类型一样,但是字符集不一样,所以索引没走
我们把user_info表的字符集做一下修改:
ALTER TABLE `user_info`
MODIFY COLUMN `phone` varchar(50) CHARACTER SET utf8mb4 NOT NULL AFTER `id`;
再执行上面的sql,查看执行计划:
可以看出索引走了
3 为何字符集不一样,会不走索引
在MySQL中,当字符集不同的字段进行联表查询时,会导致索引失效,从而无法利用索引加速查询。
这是因为MySQL在进行查询时,会将查询条件中的字符串转换为索引字段的字符集,然后再进行匹配。如果字符集不同,MySQL需要将查询条件字符串转换为索引字段字符集,这将导致索引失效。
例如,假设有两个表A和B,其中A表中的字段使用utf8mb4字符集,而B表中的字段使用gbk字符集。如果在这两个表中进行联表查询,且查询条件包含A表中的字段和B表中的字段,那么MySQL将需要将这两个字段的字符集进行转换才能进行匹配,而这将导致索引失效,从而无法利用索引进行查询。这种情况我们在上面已经经过演示了。
为了避免这种情况,可以在设计表结构时尽量统一使用同一种字符集,或者在创建索引时指定字符集。此外,还可以通过在查询语句中使用转换函数来将字符集转换为索引所在的字符集,从而使得索引得以正确匹配,从而提高查询效率。