《MySQL死锁分析的两个工具》给出了强制类型转换导致死锁的例子。有朋友问是不是类型转换打不到索引。花了1分钟说点什么。第一类:“列类型”与“where值类型”不匹配,无法命中索引,会造成全表扫描(fulltablescan)。数据准备:createtablet1(cellvarchar(3)primarykey)engine=innodbdefaultcharset=utf8;insertintot1(单元格)值('111'),('222'),('333');cell属性为varchar类型;cell是主键,即聚簇索引(clusteredindex);t1插入3条测试数据;测试语句:explainselect*fromt1wherecell=111;explainselect*fromt1wherecell='111';第一条语句where后面的值类型是整数(同表格单元格类型不匹配);第二条语句where后面的值类型是字符串(与表格的单元格类型一致);测试结果:强制类型转换,不能命中索引,需要全表扫描,即3条记录;同类型,命中索引,1条记录;画外音:讲解详见《MySQL死锁分析的两个工具》。第二类:待连接的两张表的字符编码不同,无法命中索引,会导致笛卡尔积的嵌套循环计算。数据准备:createtablet2(cellvarchar(3)primarykey)engine=innodbdefaultcharset=latin1;insertintot2(cell)values('111'),('222'),('333'),('444'),('555'),('666');createtablet3(cellvarchar(3)primarykey)engine=innodbdefaultcharset=utf8;insertintot3(cell)values('111'),('222'),('333'),('444'),('555'),('666');t2和t1字符集不同,插入6条测试数据;t3和t1字符集相同,同样插入6条测试数据;此外,t1、t2、t3的表结构完全一样;测试语句:explainselect*fromt1,t2wheret1.cell=t2.cell;explainselect*fromt1,t3wheret1.cell=t3.cell;第一次join,连接表t1和t2(不同字符集),关联的属性是cell;第一个join连接表t1和t3(相同的字符集),关联的属性是cell;测试结果:t1和t2的字符集不同,存储空间不同;当t1和t2连在一起的时候,已经遍历了t1所有的3条记录,t1的每条记录都要遍历t2的所有6条记录。真正进行了笛卡尔积循环计算(嵌套循环),索引无效;当t1和t3连接时,遍历t1的所有3条记录,t1的每条记录使用t3索引,即扫描1行记录;画外音:请放大图片。总结两类无法使用索引的隐藏情况:表的列类型与where的值类型不一致;连接表的字符编码不同;画外音:本文在MySQL5.6上测试。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
