今天一个同事问我一个关于mysql索引的问题,一共三张表,每张表都有一个唯一索引字段,从业务含义上看这三个表的含义都是一样的,假设这三个表分别为t1 t2 t3 ,t1与t2通过唯一索引字段进行左连接,t1和t3也是通过唯一索引字段进行左连接,但通过执行计划分析,一个type为eq_ref ,另一个是type为index,这是为什么呢,为什么会不一样呢,正常来说,使用同一个唯一索引字段进行关联查询应该是eq_ref,但另一个却是index呢。下面来详细说明
三张表的表结构如下
CREATE TABLE `t1` (
`id` int NOT NULL AUTO_INCREMENT,
`uid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid_UNIQUE` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4
CREATE TABLE `t2` (
`id` int NOT NULL AUTO_INCREMENT,
`uid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid_UNIQUE` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4
CREATE TABLE `t3` (
`id` int NOT NULL AUTO_INCREMENT,
`uid` varchar(45) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci NOT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid_UNIQUE` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4
执行 explain select t1.*,t2.uid from t1 left join t2 on t1.uid=t2.uid;
再执行 explain select t1.* ,t3.uid from t1 left join t3 on t1.uid=t3.uid;
第一个语句执行type=eq_ref,而第二个语句执行时type=index,同样是唯一索引字段,为什么会这样呢,刚开始遇到这个问题时一头雾水,一开始以为是表里没有数据,因为没有数据,索引还没有建立,把表里没有数据的表都插入了数据,再执行还是不一样,接下来,看了下字段的长度,想想跟长度也没啥关系,我们也对比了下字段类型,字段类型不一致可能会出现隐形转换,导致索引失效什么的,但事与愿违,字段类型都一样,究竟是什么原因引起的呢,后来另一个同事在自己电脑上看了看,分析了下原因,说是可能是mysql执行引擎进行了优化,但是我还是持怀疑的态度,3张表字段基本一样,就算是优化,怎么会是不一样呢,说不通。
后来,我在我自己的电脑上对比了下三张表的表结构看有什么不同,不对比不知道,一对比发现了t2表和t3表的uid字段的编码不一致,t2表utf8 t3表为gb2312,我觉得90%是这个原因引起的,因为我之前也遇到过编码的问题。
上一次遇到编码的问题是,编码用了latin1编码,我忘记sql语句是单表查询还是关联查询了,当时是pda手持设备扫码,批量提交到服务端,提交时,处理的特别慢,这个问题解决了好久,当时以为是手持设备的app有问题,后来经过分析确定是后端服务的问题,最后在mysql服务器上执行那条语句,发现特别慢,耗时很长,大约10几秒中时间,其实当时表数据量不大,也就几千条数据,怎么会如此慢呢,网上各种查也没查到具体原因,无意间看了下字段编码和表编码,发现表编码和字段编码对不上,而且也不应该用latin1编码,我试图把编码改为utf8,再执行sql,结果语句执行特别快,大概几十毫秒就执行完了,这个问题解决了,真的是开心的不得了,困扰了好几天,终于解决了,可以安心的睡好觉了,但遗憾的是如果之前解决问题后,写个总结文章就好了,印象应该会更加深刻了。
最后我在自己电脑上建了3张表,进行模拟测试,最后确定确实是因为字段编码的问题,把gb2312改成utf-8就好了。 都是type=eq-ref