致使MySQL索引失效的几种常见写法

最近一直忙着处理原来老项目遗留的一些SQL优化问题,因为当初表的设计以及字段设计的问题,随着业务的增加,出现了大量的慢SQL,致使MySQL的CPU资源飙升,基于此,给你们简单分享下这些比较使用的易于学习和使用的经验。mysql

此次的话简单说下如何防止你的索引失效。程序员

再说以前我先根据我最近的经验说下我对索引的见解,我以为并非因此的表都须要去创建索引,对于一些业务数据,可能量比较大了,查询数据已经有了一点压力,那么最简单、快速的办法就是创建合适的索引,可是有些业务可能表里就没多少数据,或者表的使用频率很是不高的状况下是不必必需要去作索引的。就像咱们有些表,2年了可能就10来条数据,有索引和没索引性能方面差很少多少。sql

索引只是咱们优化业务的一种方式,千万为了为了建索引而去建索引。函数

下面是我这次测试使用的一张表结构以及一些测试数据post

`CREATE TABLE user` (
  id int(5) unsigned NOT NULL AUTO_INCREMENT,
  create_time datetime NOT NULL,
  name varchar(5) NOT NULL,
  age tinyint(2) unsigned zerofill NOT NULL,
  sex char(1) NOT NULL,
  mobile char(12) NOT NULL DEFAULT '',
  address char(120) DEFAULT NULL,
  height varchar(10) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY idx_createtime (create_time) USING BTREE,
  KEY idx_name_age_sex (name,sex,age) USING BTREE,
  KEY idx_ height (height) USING BTREE,
  KEY idx_address (address) USING BTREE,
  KEY idx_age (age) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=261 DEFAULT CHARSET=utf8;
复制代码``性能

`INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight`) VALUES (1, '2019-09-02 10:17:47', '冰峰', 22, '男', '1', '陕西省咸阳市彬县', '175');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (2, '2020-09-02 10:17:47', '松子', 13, '女', '1', NULL, '180');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (3, '2020-09-02 10:17:48', '蚕豆', 20, '女', '1', NULL, '180');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (4, '2020-09-02 10:17:47', '冰峰', 20, '男', '17765010977', '陕西省西安市', '155');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (255, '2020-09-02 10:17:47', '竹笋', 22, '男', '我测试下能够储存几个中文', NULL, '180');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (256, '2020-09-03 10:17:47', '冰峰', 21, '女', '', NULL, '167');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (257, '2020-09-02 10:17:47', '小红', 20, '', '', NULL, '180');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (258, '2020-09-02 10:17:47', '小鹏', 20, '', '', NULL, '188');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (259, '2020-09-02 10:17:47', '张三', 20, '', '', NULL, '180');
INSERT INTO bingfeng.user(idcreate_timenameagesexmobileaddressheight) VALUES (260, '2020-09-02 10:17:47', '李四', 22, '', '', NULL, '165');
复制代码``学习

单个索引

一、使用!= 或者 <> 致使索引失效

`SELECT * FROM user WHERE name` != '冰峰';
复制代码``测试

咱们给name字段创建了索引,可是若是!= 或者 <> 这种都会致使索引失效,进行全表扫描,因此若是数据量大的话,谨慎使用优化

能够经过分析SQL看到,type类型是ALL,扫描了10行数据,进行了全表扫描。<>也是一样的结果。spa

二、类型不一致致使的索引失效

在说这个以前,必定要说一下设计表字段的时候,千万、必定、必需要保持字段类型的一致性,啥意思?好比user表的id是int自增,到了用户的帐户表user_id这个字段,必定、必须也是int类型,千万不要写成varchar、char什么的骚操做。

`SELECT * FROM user` WHERE height= 175;
复制代码``

这个SQL诸位必定要看清楚,height表字段类型是varchar,可是我查询的时候使用了数字类型,由于这个中间存在一个隐式的类型转换,因此就会致使索引失效,进行全表扫描。

如今明白我为啥说设计字段的时候必定要保持类型的一致性了不,若是你不保证一致性,一个int一个varchar,在进行多表联合查询(eg: 1 = '1')必然走不了索引。

遇到这样的表,里面有几千万数据,改又不能改,那种痛可能大家暂时还体会。

少年们,切记,切记。

三、函数致使的索引失效

`SELECT * FROM user` WHERE DATE(create_time) = '2020-09-03';
复制代码``

若是你的索引字段使用了索引,对不起,他是真的不走索引的。

四、运算符致使的索引失效

`SELECT * FROM user` WHERE age - 1 = 20;
复制代码``

若是你对列进行了(+,-,*,/,!), 那么都将不会走索引。

五、OR引发的索引失效

`SELECT * FROM user WHERE name` = '张三' OR height = '175';
复制代码``

OR致使索引是在特定状况下的,并非全部的OR都是使索引失效,若是OR链接的是同一个字段,那么索引不会失效,反之索引失效。

六、模糊搜索致使的索引失效

`SELECT * FROM user WHERE name` LIKE '%冰';
复制代码``

这个我相信你们都明白,模糊搜索若是你前缀也进行模糊搜索,那么不会走索引。

七、NOT IN、NOT EXISTS致使索引失效

`SELECT s.* FROM user s WHERE NOT EXISTS (SELECT * FROM user u WHERE u.name = s.name AND u.name` = '冰峰')
复制代码``

`SELECT * FROM user WHERE name` NOT IN ('冰峰');
复制代码``

这两种用法,也将使索引失效。可是NOT IN 仍是走索引的,千万不要误解为 IN 所有是不走索引的。我以前就有误解(丢人了...)。

八、IS NULL不走索引,IS NOT NULL走索引

`SELECT * FROM user` WHERE address IS NULL
复制代码``

不走索引。

`SELECT * FROM user` WHERE address IS NOT NULL;
复制代码``

走索引。

根据这个状况,建议你们这设计字段的时候,若是没有必要的要求必须为NULL,那么最好给个默认值空字符串,这能够解决不少后续的麻烦(有深入的体验<体验=教训>)。

符合索引

一、最左匹配原则

`EXPLAIN SELECT * FROM user` WHERE sex = '男';
复制代码``

`EXPLAIN SELECT * FROM user` WHERE name = '冰峰' AND sex = '男';
复制代码``

测试以前,删除其余的单列索引。

啥叫最左匹配原则,就是对于符合索引来讲,它的一个索引的顺序是从左往右依次进行比较的,像第二个查询语句,name走索引,接下来回去找age,结果条件中没有age那么后面的sex也将不走索引。

注意:

`SELECT * FROM user WHERE sex = '男' AND age = 22 AND name` = '冰峰';
复制代码``

可能有些搬砖工可能跟我最开始有个误解,咱们的索引顺序明明是name、sex、age,你如今的查询顺序是sex、age、name,这确定不走索引啊,你要是本身没测试过,也有这种不成熟的想法,那跟我同样仍是太年轻了,它其实跟顺序是没有任何关系的,由于mysql的底层会帮咱们作一个优化,它会把你的SQL优化为它认为一个效率最高的样子进行执行。因此千万不要有这种误解。

二、若是使用了!=会致使后面的索引所有失效

`SELECT * FROM user WHERE sex = '男' AND name` != '冰峰' AND age = 22;
复制代码``

咱们在name字段使用了 != ,因为name字段是最左边的一个字段,根据最左匹配原则,若是name不走索引,后面的字段也将不走索引。

关于符合索引致使索引失效的状况能说的目前就这两种,其实我以为对于符合索引来讲,重要的是如何创建高效的索引,千万不能说我用到那个字段我就去创建一个单独的索引,不是就能够全局用了嘛。这样是能够,可是这样并无符合索引高效,因此为了成为高级的搬砖工,咱们仍是要继续学习,如何建立高效的索引。

做者:一个程序员的成长
连接:https://juejin.im/post/686927... 来源:掘金 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。

相关文章
相关标签/搜索