Mysql(四)(通过索引进行优化)

1、在使用索引列查询的时候不要使用表达式进行操作

         在索引列上使用表达式或函数,会使索引失效。

ALTER TABLE `dev_device`  ADD INDEX test(`client_type_id`);

EXPLAIN SELECT * FROM `dev_device` WHERE client_type_id = 8;

例:建立client_type_id索引列,使用client_type_id进行精确查找,type为ref,使用了非主键索引进行精确查询。

         若在client_type_id列上进行表达式操作,例client_type_id + 1  =  7,索引失效,查询变成了全表扫描。

EXPLAIN SELECT * FROM `dev_device` WHERE client_type_id - 1 = 7;

2.使用索引列进行排序操作

        若需要排序的列为索引列,可以减少查询时由排序带来的性能消耗,提高查询速度。

 ALTER TABLE `dev_device`  ADD INDEX test1(`ctime`);

EXPLAIN SELECT * FROM `dev_device` ORDER BY `ctime`;

例:在查询中出现Using filesort,说明使用了文件排序,需要消耗额外的性能来进行排序

3.union all,or,in的选择

        当查询时需要用union all,or,in匹配多个行时,优先选择in。

例:使用ip进行范围查询

ALTER TABLE `dev_device` ADD INDEX test(`ip`);

         使用UNION ALL进行筛选,执行计划为两个查询,需要进行两次IO,效率较低。

EXPLAIN SELECT * FROM `dev_device` WHERE `ip` = '222.57.117.76' UNION ALL SELECT * FROM `dev_device` WHERE `ip` = '139.196.3.149';

         使用OR进行筛选,为一次查询,使用索引进行了范围查询。

EXPLAIN SELECT * FROM `dev_device` WHERE `ip` = '222.57.117.76' OR `ip` = '139.196.3.149';

         使用IN进行筛选,为一次查询,使用索引进行了范围查询。

EXPLAIN SELECT * FROM `dev_device` WHERE `ip` IN('222.57.117.76','139.196.3.149');

4.强制类型转换会使索引失效

例:phone为char类型,为他增加索引

ALTER TABLE `org_employee` ADD INDEX test1(`phone`);

        作为字符串进行查找时,用到了索引进行精确查找:

EXPLAIN SELECT * FROM `org_employee` WHERE phone = "123456789";

        若强制转换为长整型,进行查找,索引失效,走了全表扫描: 

 EXPLAIN SELECT * FROM `org_employee` WHERE phone = 123456789;

5.慎用不等于(!=  <>)

        !=,<>不等于会使索引失效,无法利用索引。

EXPLAIN SELECT * FROM `dev_device` WHERE unique_id != '6D92D67E-AC19-47C7-B08F-FAB00D691509';

6.Like要当心(%)

        当Mysql的模糊查询 % 在前面时,会使索引列失效,走全表扫描。

        因为Mysql的底层是B+树,B+树叶子节点的索引数据是连续的(根据索引列升序排序),因此当 % 在前面会使B+树不知道怎样去使用索引查询,从而使索引失效。

EXPLAIN SELECT * FROM `dev_device` WHERE NAME LIKE '%aa';

7.最左匹配原则

        Mysql的索引底层是B+树,所有的索引都在B+树的叶子节点并且是连续的,叶子节点会按照索引建的顺序进行构建,即最左边的索引会在叶子节点的最高层并按照升序进行排序,当第一个索引的列相等时,第二个索引才会小范围排序,这样就导致查询索引会首先匹配叶子节点的第一层,如果跳过第一层直接查询第二层是不会走索引的。

ALTER TABLE `dev_device` ADD INDEX test3(`name`,`ip`,`registrant_name`);

例:建立name、ip、registrant_name的组合索引, 使用name查询可以用到索引,使用registrant_name无法用到索引。

EXPLAIN SELECT * FROM `dev_device` WHERE NAME = '1f66d22d';

EXPLAIN SELECT * FROM `dev_device` WHERE registrant_name = '未关联';

8.范围查询使用组合索引

        当使用组合索引进行范围查询时,若组合索引的第一个列为范围查询,后面的索引将会失效。

ALTER TABLE `aud_vas_cd_record_log` ADD INDEX test(`ctime`,`ip`,`mac`);

EXPLAIN SELECT * FROM `aud_vas_cd_record_log` WHERE ctime = '2023-06-20 06:42:56' AND ip = '182.92.233.239' AND mac = '13:e2:5a:78:2f:3b';

EXPLAIN SELECT * FROM `aud_vas_cd_record_log` WHERE ctime > '2023-06-20 06:42:56' AND ip = '182.92.233.239' AND mac = '13:e2:5a:78:2f:3b'; 

        当组合索引所有的都为等值查找时,索引列都可以用到。 

         当组合索引前面的列为范围查找时,后面的索引将会失效。

9.使用or要注意

        当Mysql查询时使用到了or,且其中一个不是索引列时,Mysql不会走索引,会走全表扫描。

例:unique_id和name都有索引,可以使用索引进行查询

EXPLAIN SELECT * FROM `dev_device` WHERE unique_id = '31D91F64-B020-4476-962B-E5C44F293711' OR NAME = '680e4439';

         unique_id有索引,device_type_id没有索引,无法利用索引进行查询

EXPLAIN SELECT * FROM `dev_device` WHERE unique_id = '31D91F64-B020-4476-962B-E5C44F293711' OR device_type_id = 6;

10.优化深分页

        对于数据量比较大的表,当使用sql查询比较深的页数时,例如在100w数据里查询第60w条数据的十条:

SELECT * FROM `aud_vas_cd_record_log` ORDER BY ctime DESC LIMIT 600000,10;

        这条sql的执行顺序是,先查找出600010条数据,然后根据ctime进行排序,因为ctime是非聚簇索引,MySQL还需要拿到其他列上的数据,需要回表600010此也就是600010次IO,拿到其他列上的数据,最终返回最后的10条数据,因此,深分页慢的原因在于回表的IO次数比较多。

        使用内连接进行优化:

 SELECT * FROM `aud_vas_cd_record_log`
INNER JOIN(
    SELECT id FROM `aud_vas_cd_record_log` ORDER BY ctime DESC LIMIT 600000,10
) AS t ON t.id = `aud_vas_cd_record_log`.id;

         这条SQL的执行顺序是,先执行子查询查询600010个id主键进行ctime排序,因为id是聚簇索引,所以效率是很高的,之后会生成一张临时表返回需要查询的主键id,然后外层的查询会根据这10个id进行匹配,去聚簇索引里回表找其他的列,只回表了10次,因此效率是较高的。

11.更新十分频繁,数据区分度不高的字段上不宜建立索引

  • 更新会变更B+树,更新频繁的字段建议索引会大大降低数据库性能
  • 类似于性别这类区分不大的属性,建立索引是没有意义的,不能有效的过滤数据
  • 一般区分度在80%以上的时候就可以建立索引,区分度可以使用 count(distinct(列名))/count(*) 来计算

12.创建索引的列,不允许为null,可能会得到不符合预期的结果

        索引列为null值时,MySQL将不会将该行数据加入到索引中。这意味着,如果索引列为null,将会导致索引文件中缺少该行数据,从而影响查询性能。另外,当你使用查询语句如WHERE column IS NULL时,MySQL将不会使用该列的索引,这也会导致查询性能下降。

        因此,在设计数据库时,最好不要将索引列设置为null值。可以将该列设置为默认值,或使用非空约束(NOT NULL)强制要求该列数据不为空。这将确保索引可以正确地工作,并提高查询性能。        

13.当需要进行表连接的时候,最好不要超过三张表

        多张表的关联查询效率会变低,可以建立冗余字段,以空间换时间,减少关联表的IO。

        需要join的字段建立索引,数据类型必须一致。

14.能使用limit的时候尽量使用limit

        当我们明确知道只有一个数据行的时候,在筛选之后可以加limit 1,这样可以提高查询效率,去除无用的筛选。

15.单表索引建议控制在5个以内

        索引过多不仅会占用内存,且数据进行更新的时候还需要维护索引,使更新效率变慢。

16.单索引字段数不允许超过5个(组合索引)

        组合索引应小于5个,组合索引过多,会使位于后面的索引利用不上,因为前面的索引就已经筛选出了大部分数据,后面的索引就没有运用价值了,还会占用空间,影响修改的效率。

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值