• MySQL高级 避免索引失效的规则


      索引是数据库优化最常用也是最重要的手段之一, 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。很多时候我们因为而在使用SQL时违背了一些规则,导致查询未走索引,效率降低。我们希望索引生效,让执行效率提高。

      (1)全值匹配

      对索引中所有的列都指定具体值。

      比如我们现在在患者表的sex, homtown, cur_condition建立一个多列索引。因为在系统中根据这三项查询患者的的功能时提供给用户的,所以这也是一条使用率很高的SQL语句。建立索引后对我们的查询作explain查看执行情况。

    create index find_patient on s_patient(sex,hometown,cur_condition);
    explain select * from s_patient where sex='' and hometown='上海' and cur_condition='治愈';

    explain select * from s_patient where sex='' and cur_condition='治愈' and hometown='西安';
    #只要字段全,顺序可以互换

       (2)最左前缀法则

      如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。

    explain select * from s_patient where sex='';
    #符合法则

    explain select * from s_patient where hometown='上海' and cur_condition='治愈';
    #违背最左前缀法则,索引失效

    explain select * from s_patient where sex='' and cur_condition='治愈';
    #符合最左,但是跳过中间列,则只有最左列索引生效

      (3)范围查询

      包含范围查询时,范围查询列右边的列不走索引;与上面一样,左右都是指建立索引时的左右顺序,不是表序,也不是查询后where接的字段序。下面的结果中只有性别一列走了索引(通过key_len可以看出)。

    explain select * from s_patient where hometown>'1' and sex='';

       (4)索引列不加运算

      如果在索引列上进行运算操作, 列右边开始索引将失效;如果字符类别不加' '也算运算,底层会作类型转换相当于运算。下面的查询只有hospital_id走索引。

    create index find_patient2 on s_patient(hospital_id,username,hometown);
    explain select * from s_patient where hospital_id=1 and substring(username,1,0)='张三';

       (5)使用覆盖索引

      尽量使用覆盖索引,避免select *,即只访问索引包含的列,这样可以免去回表查。下图中第一条没有满足覆盖索引,Extra中的信息为Using index condition,表示用到了索引但是需要回表查询,此效率低于Using where; Using index;而系统中对这条SQL也只需要返回其中的username,所以可作此优化。

    explain select * from s_patient where username='张三' and hospital_id=1 and hometown='北京';
    explain select username from s_patient where username='张三' and hospital_id=1 and hometown='北京';

      (6)or连接

      用or分割开的条件, 如果or条件连接的列中有没有索引的,则整体索引失效。下面查询中,手机号列没有索引,导致整体查询索引为NULL。

    explain select * from s_patient where sex='' or mobile='123';

      (7)like模糊匹配

      如果仅仅是xxx%结尾的尾部模糊匹配,索引不会失效,多列索引也可以生效。如果包含%开头的头部模糊匹配,索引失效。

    explain select * from s_patient where username like '%张%';

    解决方式:覆盖索引

       (8)数据特征

      如果MySQL评估使用索引比全表更慢,则不使用索引。这种情况出现的原因是数据特征不显著,比如下面的查询,表中只有一条数据的mobile是'1234',其余的都是'123',这种情况下按='1234'查是走索引的,而如果按='123'查,MySQL会发现走索引不如遍历整表更快,则索引失效。is NULL和is NOT NULL原理相同,数据在表中太不显著,则不走索引。

    create index find_doctor on s_doctor(mobile);
    explain select * from s_doctor where mobile='123';
    explain select * from s_doctor where mobile='1234';

      (9)in走索引,not in不走索引

      下面的查询是系统中比较复杂的SQL之一,利用了子查询,如果是not in则表示找出非武汉地区患者的用药情况。

    create index med_find_patient_hometown on s_medicine(patient_id);
    explain select * from s_medicine where patient_id in (select id as patient_id from s_patient where hometown='武汉');
    explain select * from s_medicine where patient_id not in (select id as patient_id from s_patient where hometown='武汉');

      (10)单列索引与复合索引

      能使用复合索引的情况下,尽量使用复合索引而少使用单列索引。下面的例子回到最开始建的索引上。

    复合索引:

    create index find_patient on s_patient(sex,hometown,cur_condition);
    -- 相当于创建了三个索引:
    -- sex
    -- sex + hometown
    -- sex + hometown + cur_condition

    单列索引:

    create index find_patient_sex on s_patient(sex);
    create index find_patient_hometown on s_patient(hometown);
    create index find_patient_condition on s_patient(cur_condition);
    -- 数据库会使用一个最优的索引(辨识度最高的索引),而不会全使用

    以上就是使用索引时的一些规则,最后补充一个查看索引使用情况:

    show status like 'handler_read%';

    -- Handler_read_first:索引中第一条被读的次数。如果较高,表示服务器正执行大量全索引扫描(这个值越低
    -- 越好)。
    -- Handler_read_key:如果索引正在工作,这个值代表一个行被索引值读的次数,如果值越低,表示索引得到的
    -- 性能改善不高,因为索引不经常使用(这个值越高越好)。
    -- Handler_read_next :按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,
    -- 该值增加。
    -- Handler_read_prev:按照键顺序读前一行的请求数。该读方法主要用于优化ORDER BY ... DESC。
    -- Handler_read_rnd :根据固定位置读一行的请求数。如果你正执行大量查询并需要对结果进行排序该值较高。
    -- 你可能使用了大量需要MySQL扫描整个表的查询或你的连接没有正确使用键。这个值较高,意味着运行效率低,应
    -- 该建立索引来补救。
    -- Handler_read_rnd_next:在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说
    -- 明你的表索引不正确或写入的查询没有利用索引。

      

  • 相关阅读:
    dubbo记录3(配置、高可用、原理)
    dubbo记录2(运行dubbo的三种方式、与springboot整合、SpringBoot与dubbo整合的三种方式)
    dubbo记录1( 搭建注册中心、管理控制台和监控中心,第一个案例)
    vxe-table: 一个基于 vue 的 PC 端表格组件
    rabbitmq之死信队列,延迟队列,消息可靠投递
    springboot整合rabbitmq
    rabbitmq记录(2)spring整合rabbitmq--手动模式,测试消息的持久化
    rabbitmq记录(1)安装,work模式,发布订阅模式,路由模式,topic模式,spring整合rabbitmq--自动模式
    httpclient upload file
    SpringMVC自定义注解进行参数校验(转)
  • 原文地址:https://www.cnblogs.com/Kinghao0319/p/13459985.html
Copyright © 2020-2023  润新知