创建高性能索引——《高性能Mysql》笔记2

1. 索引基础及优点

  • 索引在MYSQL中也称作“键(Key)”,是一种存储引擎快速找到记录的数据结构。索引优化是对查询性能优化的最有效手段。
  • MYSQL的索引有很多种类型,不同的存储引擎支持的索引类型可能不一样。
  • 相关链接:Mysql索引基础B-tree和B+tree

实例:

  • 假设有如下数据表
CRATE TABLE People(
    last_name varchar(50) not null,
    first_name varchar(50) not null,
    dob date not null,
    gender enum('m','f')not null,
    key(last_name,first_name,dob)
);
  • 该表的B-tree存储结构如下:这里使用last_name、first_name、dob三列作为组合索引。B-Tree索引进行排序的依据是根据创建索引是列的顺序。这里先根据last_name进行排序,相同的话,再依次根据first_name、dob进行排序。
    这里写图片描述

B-Tree索引的查询类型:

  • 全值匹配:和索引中的所有列进行匹配,例如前面提到的索引可以查找姓名为Cuba Allen,出生于1960-01-01的人。
select * from Peole 
where last_name='Allen' and first_name='Cuba' and dob='1960-01-01' 
  • 匹配最左前缀:前面提到的索引可用于查找全部姓为Allen的人,即使用索引的第一列。
select * from Peole 
where last_name='Allen'
  • 匹配列前缀:也可以匹配某一列的开头部分。例如前面的例子可以查找所有以J开头的姓的人,即只使用索引的第一列。
select * from Peole 
where last_name like 'J%'
  • 匹配范围值:例如前面提到的索引可以查找姓在Allen和Barraymore之间的人,这里也只使用了索引的第一列。
select * from Peole 
where last_name > 'Allen' and last_name < 'Barraymore'
  • 精确匹配某一列并范围匹配另外一列:例如前面提到的索引可以查找姓在Allen和Barraymore之间的人,这里也只使用了索引的第一列。
select * from Peole 
where last_name = 'Allen' and first_name like 'K%'
  • 因为B-tree树是的节点是有序的,所以除了按值查找以外,索引还可以用于查询中的ORDER BY操作(按顺序查找)。

根据以上几种情况,我们能发现一个规律,在组合索引中,无论使用索引的哪些字段查询,组合索引的第一列总是要用到的,这就是组合索引的最左优先原则。

组合索引的最左优先原则:

  • 如果不是按照最左列开始查找,则无法使用索引。 例如上面例子中无法查找名字为Bill的人,也无法查找特定生日的人,因为这两列都不是最左数据列。
  • 不能跳过索引中间的列 也就是说,前面所述的索引无法用于查找姓为Smith并且在某个特定日期出生的人。如果不指定名(first_name),则MYSQL只能使用索引的第一列。
  • 如果查询中有某个列的范围查询,则其右边的所有列都无法使用索引优化查找。例如下面这个查询,这个查询只能使用索引的前两列。
select * from People
WHERE last_name='Smith' and  first_name like 'J%' and dob='1976-12-23'

索引的优点

  1. 索引大大减少服务器需要扫描的数据量
  2. 索引可以帮助服务器避免排序和临时表
  3. 索引可以将随机I/O变为顺序I/O

索引不一定是最好的解决方案

  • 对于非常小的表,大部分情况下简单的全表扫描更高效。
  • 对于中大型的表,索引就非常有效。
  • 但是对于特大型的表,建立和使用索引的代价随之增长,可能要使用其他技术例如分区。

2. 高性能索引策略

(1)独立的列

  • 下面的这个查询无法使用actor_id列的索引,因为MYSQL无法自动解析actor_id + 1 = 5为actor_id=4。
select * from actor where actor_id + 1 = 5;
  • 下面这个也是常见错误,我们应当始终将索引列放到比较符号的一侧
select ... where TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) <= 10;

(2)前缀索引与索引选择性

前缀索引

  • 如果需要索引的字符序列很长的话,那么就可以使用前缀索引,即索引开始的部分字符,这样可以大大减少索引空间,提高索引效率,但是也会降低索引的选择性。
  • MYSQL无法使用前缀索引做ORDER BY 和GROUP BY,也无法使用前缀索引做覆盖扫描

索引的选择性

  • 索引的选择性 = 不重复的索引值和数据表的记录总数的比值
  • 索引的选择性越高则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。唯一索引的选择性是1,是性能最好的索引。
  • 为了让前缀索引有较高的选择性,我们要选择合适的前缀长度(可以统计某些前缀的出现频率来得到)。
  • 常见的使用场景:对很长的十六进制唯一ID使用前缀索引。

(3)多列索引(组合索引)

  • 常见错误:为每个列创建独立的索引,或者按照错误的顺序创建多列索引。
  • 常见错误:为WHERE条件里面的列都建上索引。
  • 在多个列上建立独立的单列索引大部分情况并不能提高MYSQL的查询性能。例如下面这个例子:film_id和actor_id上各有一个单列索引:
select film_id,actor_id from film_actor
where actor_id = 1 or film_id = 1;
  • MYSQL5.0及以上版本会使用“索引合并”策略,一定程度上可以使用多个单列索引来定位指定的行,但单列索引仍然不是好的选择。

实际上索引的建立是一定要根据查询条件来设计的:

  • 多个索引做相交操作时(多个AND条件),通常意味着需要一个包含AND相关列的多列索引,而不是单列索引。
  • 多个索引做联合操作时(多个OR条件),通常需要耗费大量CPU和内存资源在算法的缓存、排序和合并操作上。特别是有些索引选择性不高,需要合并扫描返回大量数据的时候。选择性不高的索引可能会消耗更多资源,这时候还不如将查询改成UINION操作更好。

选择合适的索引列顺序:

  • 将选择性最高的列放到索引最前列。

(2)聚簇索引(聚集索引)

介绍

  • 相关链接:Mysql索引基础B-tree和B+tree

  • 聚簇索引也叫聚集索引,并不是一种索引类型,而是一种数据存储方式。

  • 当表有聚簇索引时,数据放到索引的叶子页中,但是节点页只包含索引列。
  • InnoDB通过主键聚集数据,如果没有定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。

聚簇索引的优点

  • mysql的一次磁盘读取一页的数据,而一页能包含很多的索引,聚簇索引尽可能的把索引数据保存在一起,所以查询时需要很少的磁盘I/O就能获取全部数据。例如:根据用户ID获取一个用户的全部邮件。
  • 聚簇索引把索引和数据都放到B-tree中,所以从聚簇索引中获取数据比在非聚簇索引中查找要快。
  • 使用覆盖索引扫描的查询可以直接使用页节点中的主键值。

聚簇索引的缺点

  • 聚簇索引最大限度提高了I/O密集型应用的性能,但如果数据全部放在内存中,聚簇索引就失去了优势。
  • 插入速度严重依赖于插入顺序。按照主键自增的顺序插入是最快的,但是如果不是顺序的插入就需要用OPTIMIZE TABLE命令重新组织表。
  • 更新聚簇索引列的代价很高。
  • 插入新行或者主键被更新需要移动页节点的时候,可能会面临“页分裂”的问题。当主键值要求一行被移动插入到一个已满的页中,存储引擎会将该页分裂成两个页面来容纳该行,导致占用更多磁盘空间。
  • 若行比较稀疏,或者页分裂导致数据不连续的时候,聚簇索引会使全盘扫描变慢。
  • 二级索引(非聚簇索引,也是非主键的索引,有人称作辅助索引)的页子节点包含了引用行的主键列,占用了更多空间。
  • 二级索引访问需要两次索引查找(先找到页子节点中的主键值,再去聚簇索引中找主键值对应的行)

猜你喜欢

转载自blog.csdn.net/huanglu20125/article/details/79369298
今日推荐