《高性能MySql》五.创建高性能索引

索引基础

1.存储引擎用类似的方法使用索引,其先在索引中找到对应值,然后根据匹配的索引记录找到对应的数据行。

2.mysql只能高效地使用索引的最左前缀列。创建一个包含两个列的索引,和创建两个只包含一列的索引是大不相同。

3.索引的类型

(1)索引是在存储引擎层而不是服务器层实现的。不同存储引擎的索引工作方式并不一样的。底层的实现也可能不同。

(2)B-Tree索引

如果没有指明类型,那多半是B-tree索引,使用B-tree数据结构来存储数据。

B-tree通常意味着所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同。

索引树中的节点是有序的,所以除了按值查找之外,索引还可以用于查询中的order by操作。

例: 索引中包含last_name ,first_name 和dob列的值

索引对多个值进行排序的依据是crate table 语句中定义索引时列的顺序。

索引对如下类型的查询有效: (姓,名,生日)为索引

a.全值匹配:指和所有列进行匹配

b.匹配最左前缀:可用于查找所有姓为Allen的人,即只使用索引的第一列。

c.匹配列前缀:也可以只匹配某一列的值的开头部分。例A开头的姓的人,这里也只使用了索引的第一列

d.匹配范围值:索引可用于查找姓在Allen和Barrymore之间的人,这里也使用了索引的第一列。

e.精确匹配某一列并范围匹配另外一列:即第一列last_name全匹配,第二列first_name范围匹配。

f.只访问索引的查询:

B-Tree索引的限制:

a.如果不是按照索引的最左列开始查找,则无法使用索引。例如:无法单独查找第二列,第三列数据,这两列都不是最左数据列。类似地,也无法查找姓以某个字母结尾的人

b.不能跳过索引中的列。例前面索引无法用于查找姓Allen并且在某个生日的人,跳过了名

c.如果查询中有某个列的范围查询(如:like) ,则其右边所有列都无法使用索引优化查找。例如:where last_name = "Allen" and first_name like 'J%' and dob = '1979-10-10'。这个查询只能使用索引的前两列。

(3)哈希索引

基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有索引列计算一个哈希码。

在mysql中,只有Memoroy引擎显式支持哈希索引。

因为索引自身只需存储对应的哈希值,所以索引的结构十分紧凑,这也让哈希索引查找的速度非常快。

哈希索引缺陷:

a.哈希索引数据并不是按照索引值顺序存储的,索引也就无法用于排序

b.哈希索引也不支持部分索引列匹配查找。

c.哈希重复值

索引的优点

1.索引可以让服务器快速地定位到表的指定位置。索引也有一些附加作用。

2.B-Tree索引,按照顺序存储数据。因为索引中存储了实际的列值,所以某些查询只使用索引就能够完成全部查询。

高性能的索引策略

1.独立的列

(1)"独立的列"是指索引列不能四表达式的一部分,也不能是函数的参数

(2)where actor_id + 1 = 5 ; 无法使用索引,始终将索引列单独放在比较符号的一侧。

2.前缀索引和索引选择性

(1)索引过长,模拟哈希索引。

(2)通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率。但这样也会降低索引的选择性。

(3)索引的选择性指,不重复的索引值和数据表的记录总数的比值。选择越高则查询效率越高。因为可以过滤更多的行。

(4)对于Blob,Text或者很长的varchar类型的列,必须使用前缀索引,因为MySql不允许索引这些列的完整长度。

(5)诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长。前缀应该足够长,以使得前缀索引的选择性接近于索引整个列。

(6)计算合适的前缀长度,计算列的选择性

(7)可以在一个查询中针对不同前缀长度进行计算,这对于大表非常有用。

(8)创建前缀索引

alter table sakila.city_demo ADD KEY (city(7));

前缀索引是一种能使索引更小,更快的有效办法,但另一方面也有缺点:MySql无法使用前缀索引做order by 和 group by,也无法使用前缀索引做覆盖扫描。

(9)常见场景是针对很长的十六进制唯一ID使用前缀索引。此时采用长度为8的前缀索引通常能显著地提升性能。

3.多列索引

(1)where actor_id = 1 or film_id = 1           => 在老的MySql版本中,mysql对这个查询会使用全表扫描。

(2)在Mysql5.0或更新版本,查询能够同时使用这两个单列索引进行扫描,并他们的结果进行合并。这种算法有三个变种:or条件的联合,and条件的相交,组合前两种情况的联合及相交

(3)索引合并策略有时候是一种优化的结果,但实际上更多时候说明了表上的索引建得很糟糕:

a. 当出现对多个索引做相交操作时(通常有多个And条件),通常意味着需要一个包含所有相关列的多列索引,而不是多个独立的单列索引。

b.当服务器需要对多个索引做联合操作(通常有多个or条件),通常需要耗费大量cpu和内存资源在算法的缓存,排序和合并操作中。

4.选择合适的索引列顺序

(1)当不需要考虑排序和分组时,将选择性最高的列放在前面通常是最好的。这时候索引作用只用于优化where条件的查找。

(2)考虑全局基数和选择性,而不是某个具体查询:

select count(distinct staff_id)count(*) as staff_id_selectivity, count(distinct customer_id)/count(*) as customer_id_selectivity, count(*) from payment ;           

0.0001   0.0373

选择性更高,将其作为索引列的第一列。

5.聚镞索引

(1)并不是一种单独的索引类型,而是一种数据存储方式。InnoDB的聚镞索引实际上在同一个结构中保存了B-Tree索引和数据行。

(2)因为无法同时把数据行存放在两个不同地方,所以一个表只能有一个聚镞索引。

(3)存放方式:叶子页包含了行的全部数据,但是节点页只包含了索引列。

(4)可能对性能有帮助,但也可能导致严重的性能问题

6.覆盖索引

(1)Mysql也可以使用索引来直接获取列的数据,这样就不需要读取数据行。如果索引的叶子节点中已经包含要查询的数据,那么就没必要回表查询。

(2)如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为"索引覆盖"。

(3)不是所有类型的索引都可以成为覆盖索引。覆盖索引必须存储索引列的值。所以Mysql只能使用B-Tree索引做覆盖索引。

(4)mysql能在索引中做最左前缀匹配的Like比较,因为该操作可以转换为简单的比较操作,但是如果是通配符开头的Like查询,存储引擎就无法做匹配。

7.冗余和重复索引

(1)MySql的唯一索引限制和主键限制都是通过索引实现的。如果创建了索引(A,B),再创建索引(A)就是冗余索引,因为这只是前一个索引的前缀索引。因此索引(A,B)也可以当作索引(A)来使用。(B,A)不是冗余i,(B)也不是。

8.二级索引的叶子节点包含了主键值,所以在列(A)上的索引就相当于在(A,ID)上的索引。

索引案例学习

1.尽可能将需要做范围查询的列放到索引的后面,以便优化器能使用尽可能多的索引列。

2.可以在索引中加入更多的列,并通过IN()的方式覆盖那些不在where子句中的列,但这种技巧也不能滥用,否则可能会带来麻烦。

3.支持多种过滤条件

(1) 哪些列拥有很多不同的取值,哪些列在where子句中出现得最频繁。在有更多不同值的列上创建索引的选择性更好,可以让mysql更有效过滤不需要的行。

(2)选择性不高,但很多查询都会用到,可以建议在创建不同组合索引的时候将(sex,country)列作为前缀。

(3)如果想尽可能重用索引而不是建立大量的组合索引,可以使用in()的技巧来避免同时需要(sex,coutry,age) 和 (sex,country,region,age)的索引。

(4)选择性高,使用也不频繁,可以选择忽略它们,让mysql多扫描一些额外的行即可。

(5)age放在索引最后,总是尽可能让mysql使用更多的索引列,因为查询只能使用最左前缀,直到遇到第一个范围条件列,age列多半是范围查询。

4.避免多个范围条件

(1)对于范围条件查询,MySql无法再使用范围列后面的其他索引列。in()没有这个限制

(2)last_online列和age列,MySql可以使用last_online列索引或者age列索引,但无法同时使用他们。

5.优化排序

维护索引和表

1.找到并修复损坏的表,维护准确的索引统计信息,减少碎片

2.找到并修复损坏的表

(1)check talbe : 找到

(2)repair table : 修复损坏的

3.减少索引和数据的碎片

(1)B-Tree索引可能会碎片化,,这会降低查询的效率。碎片化的索引可能会以很差或者无序的方式存储在磁盘上

(2)可以通过先删除,然后再重新创建索引的方式来消除索引的碎片化

总结

1.大多数情况下都会使用B-tree索引

2.索引覆盖查询是很快的,如果一个索引包含了查询需要的所有列,那么存储引擎就不需要再回表查找行,这避免了大量的单行访问。

工具

1.explain : 查看优化器如何决定执行查询的主要方法。

(1)id :包含一组数字,表示查询中执行select子句或操作表的顺序

a. id相同,执行顺序由上至下

(3)type :表示mysql在表中找到所需行的方式,又称“访问类型”,常见类型:All, index, range, ref, eq_ref, const, system, null

a. All : MySQL将遍历全表以找到匹配的行

b.index:Full Index Scan,index与ALL区别为index类型只遍历索引树

c.range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行。显而易见的索引范围扫描是带有between或者where子句里带有<, >查询。当mysql使用索引去查找一系列值时,例如IN()和OR列表,也会显示range(范围扫描),当然性能上面是有差异的。

d.ref:使用非唯一索引扫描或者唯一索引的前缀扫描,返回匹配某个单独值的记录行

e.eq_ref:类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

f.const、system:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量

g.NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成

(3)https://www.cnblogs.com/xuanzhi201111/p/4175635.html

资源

1.组合索引的使用场景:https://www.cnblogs.com/zhengyun_ustc/p/slowquery2.html

2.show index from talbe_name ;  //查看表的索引

猜你喜欢

转载自blog.csdn.net/weixin_42763504/article/details/85395631
今日推荐