《高性能MySQL》第5章 创建高性能的索引

5.1 索引基础

索引是存储引擎快速找到记录的一种数据结构,因为在引擎层,所以没有统一的标准。
如果没有特别说明,一般的索引指B-Tree索引,InnoDB用的B+树
《高性能MySQL》第5章 创建高性能的索引_第1张图片

不需要全表扫描,而是从索引根节点开始搜索。
根节点的槽中存放指向子节点的指针。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。

叶子节点比较特别,他们的指针指向的是被索引的数据,而不是其他的节点页。
树的深度和表的大小直接相关。

前面所述的索引树对如下类型的查询有效

  • 全值匹配:和索引中所有列进行匹配
  • 匹配最左前缀:只使用索引的第一列
  • 匹配列前缀:匹配某一列的值的开头部分
  • 匹配范围值:比如匹配姓在Allen和Barrymore之间的人。这里也只使用索引第一列
  • 精确匹配某一列并范围匹配另外一列:比如查找姓张名三的人
  • 只访问索引的查询

下面是B-Tree索引的限制:

  • 如果不是按照索引的最左列开始查找,则无法使用索引
  • 不能跳过索引中的列:如果不指定名,则MySQL只能使用索引的第一列
  • 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引(LIKE是一个范围条件查找)

哈希索引
基于哈希表实现,只有精确匹配索引所有列的查询才有效。
对于每一行数据,存储引擎会对所有的索引列计算一个哈希码(代表对象的特征,同一个类的对象按照自己的不同特征尽量有不同的哈希码)。哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存在索引中,同时在哈希表中保存指向每个数据行的指针。

在MySQL中,只有Memory引擎显示支持哈希索引。它同时支持B-Tree索引。值得一提的是,它支持非唯一哈希索引。
《高性能MySQL》第5章 创建高性能的索引_第2张图片
先计算Peter的哈希码,然后找value即指向第N行的指针,最后判断第N行值是否为Peter

  • 哈希索引查找速度非常快,但它的限制是:
  • 哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。
  • 哈希索引数据不是按照索引值顺序存储的,所以就无法排序
  • 哈希索引也不支持部分索引列匹配查找,哈希索引始终是使用索引列的全部内容来计算哈希值的。如数据列(A,B)上建立索引,如果查询只有数据列A则无法使用索引
  • 只支持等值比较查询
  • 出现哈希冲突(不同索引列值有相同哈希值)时,存储引擎必须遍历链表中所有行指针,逐行进行比较。

InnoDB引擎有一种特殊功能叫”自适应哈希索引“,当索引值被频繁使用时,它会在内存中基于B-Tree索引上再创建一个哈希索引。


创建自定义哈希索引
SELECT id FROM url WHERE url=”http://www.mysql.com”
AND url_crc=CRC32(“http://www.mysql.com“)
这样实现的缺陷是需要维护哈希值,可以手动维护,也可以使用触发器实现。
不要用SHA1和MD5作为哈希函数,因为他们计算出来的哈希值是非常长的字符串,浪费大量空间。

一个简单的办法可以使用MD5()函数的返回值的一部分来作为自定义哈希函数。这样实现最简单。

要避免冲突问题,必须在WHERE条件中带入哈希值和对应列值。

空间数据索引(R-Tree):会从所有维度索引数据
全文索引


5.2 索引的优点

  1. 大大减少了服务器需要扫描的数据量
  2. 帮助服务器避免排序和临时表。
  3. 将随机IO变为顺序IO

5.3 独立的列

查询的列不是独立的,就不会使用索引。
独立的列是指索引列不能是表达式的一部分,也不能是函数的参数。


5.3.2 前缀索引性和索引选择性
索引选择性指:不重复的索引值和数据的记录总数的比值。索引的选择性越高则查询效率越高。

为了决定前缀的合适长度,需要找到最常见的值的列表,然后和常见的前缀列表进行比较。

计算合适的前缀长度的另一个办法是:计算完整列的选择性,并使前缀的选择性接近于完整列的选择性。

比如前缀为4最常出现的城市的次数,看是不是基本均匀一致
会不会最常出现的前缀的出现次数(可能只有三个字母)比最常出现的城市的出现次数大得多。

前缀索引是能使索引更小,更快的有效方法,但缺点:MySQL无法用前缀索引做ORDER BY和GROUP BY,也无法使用前缀索引做覆盖扫描。

后缀索引:可以把字符串反转后存储,并基于此建立前缀索引


5.3.3 多列索引
在多个列上建立独立的索引大部分情况并不难提高Mysql的查询性能。
在Mysql5.0后的版本,将结果进行合并,用OR条件的联合(UNION),AND条件的相交(intersection)。

5.3.4 选择合适的索引列顺序

将选择性最高的列放到索引最前列。通常不如避免随机IO和排序那么重要

5.3.5 聚簇索引

不是一种单独的索引类型,而是一种数据存储方式。它的数据行存放在索引的叶子页中。聚簇表示数据行和相邻的键值紧凑地存储在一起。因为数据行不能放在两个地方,所以一个表只能有一个聚簇索引。
《高性能MySQL》第5章 创建高性能的索引_第3张图片
因为是存储引擎负责索引,不是所有的存储引擎都支持聚簇索引。
索引列包含了整数值,叶子页包含了行的全部数据。

如果没有定义主键,InnoDB会选择一个唯一的非空索引作主键,如果没有这样的索引,InnoDB会隐式定义一个主键作聚簇索引

优点:

  1. 将索引和数据保存在同一个B-Tree中,访问快
  2. 可以把相关数据保存在一起,例如用户邮箱,根据用户ID来聚集数据
  3. 覆盖索引扫描的查询可以直接使用页节点的主键值

缺点:

  1. 数据全放在内存里,顺序不重要,聚簇索引没必要
  2. 插入速度严重依赖插入顺序(按主键顺序插入)
  3. 更新聚簇索引列的代价高

5.3.6 覆盖索引

如果一个索引包含所有需要查询的字段的值(索引列的值),称它为覆盖索引
优点:

  1. 索引条目远小于数据行大小
  2. 索引按列值存储的,对于IO密集型的范围查询比随机IO少得多
  3. 对InnoDB表很有用,InnoDB的二级索引在叶子节点中保留了行的主键值,如果二级主键能覆盖查询,则可以避免对主键索引的二次查询

MySQL不能在索引中执行LIKE操作

查询只能使用索引的最左前列,直到遇到第一个范围查询为止
随着偏移量的增加,MySQL花大量时间扫描已放弃的数据,反范式化,预先计算和缓存是唯一的办法。

另一种是延迟关联。使用覆盖索引查询返回需要的主键。再通过主键关联原表获得需要的行。

你可能感兴趣的:(数据库)