0
点赞
收藏
分享

微信扫一扫

sql进阶:实测索引失效的条件和情景

其实这个文章应该早早就写了,但是一直拖着,毕竟sql一直是个忽略的点。
看过那本sql必读必会,然后就没然后了,我不知道是我看的版本问题还是咋的,拍胸脯保证,真的全本书上多是实践操作的语法,不同版本数据库的区别,对比和写法,也有索引的创建,然后呢?好像是仅仅提了几个索引会失效的原则,例如in,例如like。
然后在那以后的工作中宁可看看框架,看看具体的方法,看看redis,看看elasticsearch。与人一说在研究cloud,研究es,研究分布式,研究消息队列。高大上又自我满足。
曾经我觉得sql有什么好学的?不就是增删改查么?不就是优化么?看过简单的优化的教程,亲自做过几个demo,大概知道什么表锁行锁事务隔离级别,也会建个索引,什么唯一,主键,复合。然后语法都会,自以为也就这样了。
你要是问我复杂sql?多关联查询?我甚至还能理直气壮的告诉你,所谓的关联查询不也就是简单查询拼出来的么?哪有什么不可拆分?(现在想想觉得自己真的蠢的可怜)
第一次开始怀疑自己是一次面试,面试官很温和,问的也很常见。聊到sql的时候从简单的索引问到了复合索引。看过我上一篇文章的朋友应该知道,复合索引我其实知道的太多,但是简单的原理还是稍微懂一点点,我也以为懂这么一点点够用了。有兴趣的朋友也可以点进去看看。
sql优化及讲解


然后面试官问了一个问题。mysql数据库,现在A,B,C三个字段设置成联合索引,如果查询条件A>5会不会走索引?这个没啥问题,肯定走啊。。。自以为是的我有多信心满满现在脸有多疼。

查询数量是超过表的一部分,mysql30%,oracle 20%会导致索引无法使用。

这个我要放在第一个说,因为我也是多方求证,做了demo才相信的。
我用了比较极端的例子,建个表插入age>0的几条随机的数据,然后age设置索引,查询条件age>-1.结果发现确实是没走索引。
这个表结构虽然很简单,但是我用这个表做了好多demo,所以也贴出来一下。


这个是正常一点的查询,然后也走了索引,让大家知道范围查询也可能走索引的


这个就是我说的极端的情况了,然后没走索引


然后现在继续说面试的那个题,A>5会不会走索引?还真不一定。

什么是负向查询?查询肯定不能命中索引。会导致索引无用。

这个其实还稍微好理解一点,比如说过我们查寻条件age!=-1,但是其实我们查询条件中age没有等于-1的。也就是全表扫描,索引也会失效(其实这个很上面的例子有点像,不走索引的原因可能也是因为上面那个,因为非命中所以肯定得到的结果也是全部。。不确定,但是不冲突,知道这样会不走索引就行了)
我刚刚看了下,age没有14的,所以就用了14,其实只要不命中都可以。


大于小于和between in到底走不走索引?

这里要声明。我之前看到的in会导致索引失效是以前的,现在优化后in不一定了。至于走不走索引还是看范围。
in到底会不会让索引失效?答案是不一定。看下面两个图片的对比。区别只是in的数值命中不同。第一张都中了,第二张都没中。其实这个还是可以理解为第一条,也就是数据范围的原因



between and 和<>有区别?没有的!不要相信网上那些过时言论或者胡说八道



接下来是两个都不走索引的例子:



好了,差不多这几个范围的例子就做到这里,由此可见,网上的好多言论都是不实的,不要瞎相信。

复合索引不是以为的那么简单,谁说顺序不能变?

其实这个概念,可能不是别人瞎说,而是以前的版本就是那样,但是现在随着更新优化,也该接触新知识了。A,B,C复合索引,条件上where A=1 AND C=2 AND B=3.到底会不会走索引?



接下来运行的结果:
这个是正常顺序A,B,C顺序写的,走了索引


这个有点不太正常的顺序,A,C,B写的。然後还是三个索引都用了(从key_len可以看出来,只走age长度是5,age,id长度是10,都走了长度是53)。


A,B,C的复合索引,查询A,C,结果只有A走了索引,因为key_len长度是5.


A,B,C的复合索引,查询C,B,A条件都是等于,结果还是走完整索引!


注意!!!!下面两个都是没走索引的,只不过因为我太懒了就三个字段还都是索引,所以查询的时候怎么也是index。


是不是觉得贼神奇?超乎你的常识?这是因为mysql优化。

其实 = 和 in 是可以乱序的,比如 a=1 and b=2 and c=3,建立(a,b,c)索引可以任意顺序,mysql查询优化器会帮助我们调整顺序。

接下来我们验证第二点:最左匹配原则:

mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a,b,c联合索引,条件a=1 and b>2 and c=3 ,如果建立(a,b,c)顺序的索引,c就用不到索引;如果建立(a,c,b)的索引则都可以用到,a,c的顺序是可以随意调整的(原因是第一条)。这就是最左匹配原则。

如果你理解不了为什么会这样,仔细看看下面这个图(这是一个b+树索引图)。


下面是实际在数据库查询的截图:
很明显只有age走了索引,因为key_len的长度是5


这个图是age和id都走了,虽然等级一样但是看key 的长度是有区别的


这个是age和id都走了索引,因为name和age是等于,可以随意调顺序。这个sql语句和select * from demo where age=12 and id>0 and name='aa'是一样的。


三个都走了索引,看kye_len长度吧。因为我name是个字符串,所以不能用<>来举例,!=也差不多效果。反正是三个索引都走了


然後这个也证明了上文中提到了的最左原则。至于为什么会这样,看那个B+树结构图,仔细看看很容易理解。
这里说明,B+树,BitMap索引,Hash索引是不一样的。我也才看具体的区别,有时间会做个笔记。
剩下常见的索引失效情况就不多说了,简单的列出来,大家尽量避免就好了:

  • like以通配符开头('%abc')mysql会使用全表扫描。
  • 字符串不加单引号索引失效。(因为涉及到类型转换)
  • 少用or,用它来连接可能会导致索引失效。(注意是可能!!!不是一定)。
  • 不在索引列上做任何操作(计算、函数、类型转换),会导致索引失效而转向全表扫描。
    然後我今天看到一个文章,编了一个顺口溜挺好的,虽然说得有些不太准确,但是起码好记啊,在这附上图片和文章地址:
    https://www.jianshu.com/p/d5b2f645d657

好了,今天就到这里了。争取每天学习一点点,不知道多久会发生质变,哈哈。然后大家共勉,祝大家工作生活顺顺利利的吧!
全文手打不易,如果你觉得有帮到你或者有点用,别吝啬的点个喜欢和点个关注哦~~

举报

相关推荐

0 条评论