MySQL 高级--优化 —— 创建索引原则使用场景和索引失效的情况

Posted 猎人在吃肉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 高级--优化 —— 创建索引原则使用场景和索引失效的情况相关的知识,希望对你有一定的参考价值。

文章目录

1、创建索引的原则

1.1、最左前缀匹配原则

mysql会一直向右匹配直到遇到范围查询 (>、<、between、like) 就停止匹配。
比如 a = 1 and b = 2 and c > 3 and d = 4 ,如果建立 (a,b,c,d) 顺序的索引,d是用不到索引的,如果建立 (a,b,d,c) 的索引则都可以用到,a,b,d的顺序可以任意调整。

1.2、=和in可以乱序

比如 a = 1 and b = 2 and c = 3 建立(a,b,c) 索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。

1.3、选择 区分度高的列作为索引

区分度的公式是 count(distinct col)/count(*) ,表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。

1.4、索引列不能参与计算,保持列“干净”

比如 from_unixtime(create_time) = ’2014-05-29’ 就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成 create_time = unix_timestamp(’2014-05-29’);

1.5、尽量的扩展索引,不要新建索引

比如表中已经有a的索引,现在要加 (a,b) 的索引,那么只需要修改原来的索引即可。

2、索引的使用场景

2.1、匹配全值

对索引中所有列都指定具体值,即对索引中的所有列都有等值匹配的条件。

#设置组合索引(rental_date,inventory_id,customer_id)为唯一索引。
EXPLAIN 
SELECT  * 
FROM  rental 
WHERE rental_date = '2005-05-25 17:22:10' 
  AND inventory_id = 373 
  AND customer_id = 343 ;

2.2、匹配值的范围查询

对索引值进行范围查找。

#设置索引idx_fk_customer_id(customer_id)
EXPLAIN 
SELECT * 
FROM  rental 
WHERE customer_id >= 373 
  AND customer_id < 400 ;

2.3、匹配最左前缀

仅仅使用索引中的最左边列进行查询。比如组合索引(col1,col2,col3)能够被col1,col1+col2,col1+col2+col3的等值查询利用到的。

#创建索引idx_payment_date(payment_date,amount,last_update);

EXPLAIN SELECT * FROM payment WHERE payment_date='2006-02-14 15:16:03' AND last_update='2006-02-15 22:12:32' ;

从结果可以看出利用了索引,但又row为182行,所有只使用了部分索引。

EXPLAIN  SELECT  * FROM payment WHERE amount = 3.98   AND last_update = '2006-02-15' ;

从结果看出,这次查询没有利用索引,进行了全表查找。

2.4、仅对索引查询进行查询

当查询列都在索引字段中。即select中的列都在索引中。

EXPLAIN SELECT  last_update FROM  payment WHERE payment_date = '2005-08-19 21:21:47'   AND amount = 4.99 ;

extra部分Using index,说明不需要通过索引回表,Using index就是平时说的覆盖索引扫描(即找到索引,就找到了要查询的结果,不用再回表查找了)。

2.5、匹配列前缀

仅仅使用索引的第一列,并且只包含索引第1列的开头部分进行查找。

#创建索引 idx_title_desc_part(title(10),description(20));

EXPLAIN  SELECT title FROM  film_text  WHERE title LIKE 'AFRICAN%' ;

2.6、索引部分等值匹配,部分范围匹配

EXPLAIN 
SELECT inventory_id 
FROM  rental 
WHERE rental_date = '2006-02-14 15:16:03' 
  AND customer_id >= 300 
  AND customer_id <= 400 ;

type=ref,说明使用了索引。

2.7、列名是索引,is null,使用索引

EXPLAIN   SELECT  * FROM  payment  WHERE rental_id IS NULL ;

3、索引失效的情况

3.1、复合(组合)索引,不满足最左原则

复合索引 如idx_tab_abc ( a , b , c) 时,有效的索引只有3种: (a) ,(a,b) 、 ( a , b ,c) 。

3.2、复合(组合)索引时,范围条件 ( >、>=、<、<= 、between and 、in 等) 右边的列索引失效

范围条件 包括 >、>=、<、<= 、between and 、 in 等。

执行 explain select * from tb_emp where remark='aaa' 时:

执行 explain select * from tb_emp where remark='aaa' and deptid>1 时:

执行 explain select * from tb_emp where remark='aaa' and deptid>1 and name='jack' 时:

由此可见,在idx_remark_deptid_name ( remark ,deptid ,name ) 复合索引中,当 deptid 使用范围条件时,deptid 列 的索引依然有效, 只有范围条件后面的列(如 name)的索引将失效。

3.3、like查询以%开头,当前列和后面列的复合索引可能失效,但是覆盖索引能解决

在下图示例不太好,没有显示出复合索引中,like 前面列的索引是有效的。

3.4、不等于(!=),索引失效

3.5、is null、is not null 索引失效

is null 索引失效 :

is not null 索引失效 :

3.6、字符串不加引号,索引失效

如果字段的类型是字符串,值要用引号,否则不使用索引。

数据类型出现隐式转化,不会使用索引。

3.7、 or 前后不是同一列,索引失效

or 前后都是remark列,索引有效:

or 前面是 remark,后面是 name ,索引无效:

3.8、select 查询需要的列,不要select * ,用覆盖索引,能解决上面的索引失效的问题

Extra 列显示 Using index , 就说明使用 覆盖索引, 查询效率是最好的。

以上是关于MySQL 高级--优化 —— 创建索引原则使用场景和索引失效的情况的主要内容,如果未能解决你的问题,请参考以下文章

MySQL高级篇——索引的创建与设计原则

MySQL高级篇——索引的创建与设计原则

「MySQL高级实战篇」10分钟探索MySQL索引原理,设计原则

mysql有几种索引类型?使用索引时都有那些地方要注意?sql优化原则

MySQL高级 之 order bygroup by 优化

MySql 创建索引原则