MySQL优化(5):索引失效分析、in与exists使用场合

一、索引失效的情况

  前文提及过可以通过explain的possible_keys、key属性判断索引是否失效,key如果为null,可能是索引没建,也可能是索引失效,下面列举一些会使索引失效的情况。

1、全值匹配:顺序、个数与索引一致

2、最佳左前缀法则:查询从索引的最左前列开始并且不跳过索引中的列,中间跳过的值,后面的索引会失效

3、索引列上做了操作(计算、函数、自动或手动类型转换),会导致索引失效而转向全表扫描

4、存储引擎不能使用索引中范围条件右边的列

  

  name字段用于查找,age>11也用到了,但着重用于排序,pos则没用到索引

5、尽量使用覆盖索引(索引列和查询列一致),减少select *

  using where是在表里检索,using index会直接从索引里检索

  

  这里也是范围检索,但与上面不同的是这里从索引里获取数据,没有用到age

  

6、mysql在使用不等于(!= 或 <>)时无法使用索引

  

7、is null,is not null也无法使用索引

8、like以通配符开头(‘%abc..’)也会导致索引失效

  通过覆盖索引可以解决like ‘%字符串%‘索引失效的问题

  例:假设以name,age字段建索引

create index idx_user_nameAge on tb_user(name,age);

  查询字段只要有一个和覆盖索引沾边就行

  

  

  但如果有超过索引的部分,索引就用不上了,所以用select * 就不能使用覆盖索引

  

9、字符串不加单引号,该字段以后的索引失效

10、少用or,用它来连接时会索引失效

  

11、少数据值的列也不应该增加索引,只有两种情况,且平均分布,加了索引反而降低速度

12、range的包含范围有一定的阈值,超过会进行全文扫描

二、in与exists使用场合

  坚持小表驱动大表的原则

in:当B表的数据集必须小于A表的数据集时,in优于exists

select * from A where id in (select id from B)
#等价于:
  for select id from B
  for select * from A where A.id = B.id

exists:当A表的数据集小于B表的数据集时,exists优于in

  将主查询A的数据,放到子查询B中做条件验证,根据验证结果(true或false)来决定主查询的数据是否保留

  子查询也可以用条件表达式、其他子查询或join来替代,何种最优需具体问题具体分析

select * from A where exists (select 1 from B where B.id = A.id)
#等价于
    for select * from A
    for select * from B where B.id = A.id
#A表与B表的ID字段应建立索引

三、对Order By的优化

1、用order by子句的重点是是否会产生filesort。建索引时已经排好序,所以order by的顺序和索引最好一致,避免再一次排序。 

  

  所建的索引默认升序,一升序一降序会产生内排序

  

2、状态最好是using index,让mysql通过扫描索引本身完成排序。

  能使用index方式排序的情况:order by语句使用索引最左前列,或where子句与order子句条件组合满足索引最左前列。

 (1)order by语句使用索引最左前列,order by后字段同为asc或desc都行

    

 (2)加上where子句的条件与order by子句条件列组合满足索引最左前列

  

 (3)不能使用索引的情况

  

  假如以category_id、comments、views的顺序建索引

  

3、filesort的两种算法

 (1)双路排序:两次扫描磁盘(读取行指针和order by列,对他们进行排序,然后扫描已排好序的列表,重新列表读取数据输出)。

 (2)单路排序:mysql4.1版本后,从磁盘读取查询需要的所有列,按order by列在buffer对它们排序,然后扫描排序后的列表输出,只读取一次数据,且把随机IO变为顺序IO,但会使用更多空间,因为它把每一行都保存在内存中。

    单路排序存在的问题:

    因为要把所有字段取出,可能要取出的大小超出sort_buffer容量,导致每次只能取sort_buffer容量大小的数据进行排序(创建tmp文件,多路合并),排完再取sort_buffer容量大小的数据,反而会导致更多I/O操作。

4、order by优化策略:

 (1)单路多路算法的数据都有可能超过sort_buffer_size,超出后会建tmp文件进行合并排序,导致多次I/O,可以根据系统能力增大sort_buffer_size参数设置

 (2)增大max_length_for_sort_data参数,会增加用单路排序的概率,但如果设太大,也会更容易使数据超过sort_buffer_size,当query的字段大小总和小于max_length_for_sort_data且排序字段不是text/blob类型时,才会用单路排序,否则还是用多路排序。

 (3)order by时不要用select *,只select需要的字段,多余的字段会占用sort_buffer的内存。

5、group by: 

  适用order by原则,实质先排序后分组,遵守索引建的最佳左前缀,使用不当会产生临时表。

  

  当无法使用索引列,增大max_length_for_sort_data和sort_buffer_size参数设置。能在where的条件就不放在having里。

四、案例,其他注意点

  假如以c1,c2,c3,c4的顺序建立索引

1、对于常量类型,查询优化器会自动调优SQL,顺序不影响

   

2、范围之后全失效,但查询优化器会先常量类型自动调优,c3被调前,c4后的失效,但c4是最后一个了,所以仍用到4个。以上的例子中间并没有断

   

3、都只用到了c1,c2,第三条语句无法使用到索引排序,所以mysql内部自己进行了一次排序(前两个c3没用到查找,但用到了排序,所以无using filesort,只是没有记录到key_len里)

  

4、order by不按索引顺序会出现using filesort,本来照理第一个按order by c3,c2排序会出现filesort,但是前面已经有c2=‘a2’的条件,c2已经是常量值,所以c2其实不用排序

  

五、多表连接在从表加索引可以提高速度

案例1:两表连接的情况,多表连接时在主表还是从表建索引的问题

  如未使用索引的情况

  

  左连接把索引建在从表的关联字段比较好,主表一定会有,从表才是检索的关键

  

案例2:三表关联要建在哪些字段上

  没建索引的时候

  

  在第二、三个从表的关联字段加索引

ALTER TABLE `phone` ADD INDEX z(`card`);
ALTER TABLE `book` ADD INDEX Y(`card`); 

    

结论:

  (1)join语句中被驱动表上join条件字段加索引可以提高效率;

  (2)当无法保证被驱动表的join条件字段被索引且内存资源充足的前提下,不要太吝啬JoinBuffer的设置。

原文地址:https://www.cnblogs.com/zjxiang/p/9160810.html

时间: 2024-10-06 14:11:02

MySQL优化(5):索引失效分析、in与exists使用场合的相关文章

mysql 优化之索引的使用

mysql 优化之索引的使用 1:MySQL 索引简介: MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车. 拿汉语字典的目录页(索引)打比方,我们可以按拼音.笔画.偏旁部首等排序的目录(索引)快速查找到需要的字. 索引分单列索引和组合索引.单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引.组合索引,即一

MySQL高级 之 索引失效与优化详解

案例所用的表结构.索引.与数据如下:   索引失效与优化 1.全值匹配我最爱 2.最佳左前缀法则(带头索引不能死,中间索引不能断) 如果索引了多个列,要遵守最佳左前缀法则.指的是查询从索引的最左前列开始 并且 不跳过索引中的列. 正确的示例参考上图. 错误的示例: 带头索引死:  中间索引断(带头索引生效,其他索引失效):  3.不要在索引上做任何操作(计算.函数.自动/手动类型转换),不然会导致索引失效而转向全表扫描 4.mysql存储引擎不能继续使用索引中范围条件(bettween.<.>

mysql优化之索引建立的规则

索引经常使用的数据结构为B+树.结构例如以下 如上图,是一颗b+树,关于b+树的定义能够參见B+树,这里仅仅说一些重点.浅蓝色的块我们称之为一个磁盘块,能够看到每一个磁盘块包括几个数据项(深蓝色所看到的)和指针(黄色所看到的),如磁盘块1包括数据项17和35.包括指针P1.P2.P3.P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块.真实的数据存在于叶子节点即3.5.9.10.13.15.28.29.36.60.75.79.90.99. 非叶子节点仅仅不存储真

MySQL和Lucene索引对比分析

MySQL和Lucene都可以对数据构建索引并通过索引查询数据,一个是关系型数据库,一个是构建搜索引擎(Solr.ElasticSearch)的核心类库.两者的索引(index)有什么区别呢?以前写过一篇<Solr与MySQL查询性能对比>,只是简单的对比了下查询性能,对于内部原理却没有解释,本文简单分析下两者的索引区别. MySQL索引实现 在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式. M

MySQL优化(4):explain分析

Explain是Mysql的自带查询优化器,负责select语句的优化器模块,可以模拟优化器执行SQL查询语句,从而知道Mysql是如何处理SQL的,语法也很简单:Explain + SQL 以下是通过explain查询出的几个属性   (常见性能瓶颈 -- CPU:CPU饱和一般发生在数据装入内存或从磁盘上读取数据时 IO:磁盘I/O瓶颈发生在装入数据远大于内存容量时 服务器硬件的性能瓶颈:top,free,iostat,vmstat来查看系统的性能状态) 用途: (1)表的读取顺序,id (

mysql优化之索引

Mysql优化之使用索引 1,索引简介 索引是单独一种数据结构,单独存在的一个空间.可以把数据表里的建立了索引的字段,进和物理地址,存在在一块,这块空间就是'索引'. 查询数据先从索引中查询,查询到之后,可以直接定位到物理地址,通过物理地址,直接找到真实数据.查询会更快速. 索引是一种 以空间换时间的一种方式,牺牲了空间和写的速度,提高了查询速度 2,准备演示数据表 这里以myisam引擎的数据库为例,我准备了一张1800000条数据的表,这张表存储时包含了三个文件,.Frm是表结构文件,.MY

mysql优化之索引优化

Posted by Money Talks on 2012/02/23 | 第一篇 序章第二篇 连接优化第三篇 索引优化第四篇 查询优化第五篇 到实战中去 索引优化 索引优化涉及到几个方面,包括了索引的类型.如何让查询使用索引,查询是索引算法的选择等等操作.(原文链接http://ddbiz.com/?p=961)涉及到数据库的查询时,大多数情况都是要建立索引的,MySQL的索引类型以及创建索引方式,可以参考其文档或者这里. 服务器参数设置 在于索引有关系的数据库参数中,有一些特别重要,如下:

SQL优化避免索引失效

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0 3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放

mysql优化----explain的列分析

sql语句优化: 1: sql语句的时间花在哪儿? 答: 等待时间 , 执行时间. 等待时间:看是不是被锁住了,那就不是语句层面了是服务端层面了,看连接数内存. 执行时间:到底取出多少行,一次性取出1万行那是你的sql语句写的失败,二是扫描多少行,扫描多少行需要技术来分析,通过explain来分析. 可以重构查询和切分查询. 2: sql语句的执行时间,又花在哪儿了? 答:a: 查 ----> 沿着索引查,甚至全表扫描b: 取 ----> 查到行后,把数据取出来(sending data) 3