MySQL读书学习笔记(三)——高性能索引

索引(MySQL也叫key)是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能非常关键,尤其当表的数据量越来越大时。

3.1 索引基础

3.1.1 索引类型

B-Tree索引

默认的索引类型。大多数MySQL引擎都支持这种索引。

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

B-Tree索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据,而是从索引的根节点进行搜索。根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。最终存储引擎要么是找到对应的值,要么该记录不存在。

叶子节点比较特别,他们指向被索引的数据,而不是其他节点页。

哈希索引

哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。对每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。

在MySQL中,只有Memory引擎显式支持哈希索引。

空间数据索引

MyISAM支持空间索引,可以用作地理数组存储。和B-Tree索引不同,这类索引无需前缀查询。空间索引会从所有维度来索引数据。查询时,可以有效使用任何维度来组合查询。

全文索引

全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值。

3.2 索引的优点

索引大大减少服务器需要扫描的数据量。

帮助服务器避免排序和临时表。

随机I/O变成顺序I/O。

3.3 高性能的索引策略

3.3.1 独立的列

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

3.3.2 前缀索引和索引选择性

有时候需要索引很长的字符列,这会让索引变得大且慢。

通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率。但这样会降低索引的选择性。索引的选择性是指,不重复的索引值和数据表的记录总数(#T)的比值,1/#T到1之间。索引的选择性越高则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

一般情况下某个列前缀的选择性也是足够高的,足以满足查询的性能。对于BLOG,TEXT或者很长的VARCHAR列,必须使用前缀索引,因为MySQL不允许索引这些列的全部长度。

3.3.3 多列索引

在多个列上建立独立的单列索引大部分情况下不能提供MySQL的查询性能,MySQL引入一种“索引合并”策略,一定程度上可以使用表上的多个单列索引来定位指定的行。

3.3.4 选择合适的索引列顺序

正确的顺序依赖于使用该索引的查询,并且同时需要考虑如何更好地满足排序和分组的需要。

将选择性最高的列放到索引最前列。这在某些场景可能有用,但通常不然避免随机I/O和排序那么重要,考虑问题需要更全面。

当不需要考虑排序和分组时,将选择性最高的列放在前面通常是很好的。这时候索引的作用只是优化where条件的查找。这种情况下,这样设计的索引确实能够最快地过滤出需要的行,对于在where子句中只使用了索引部分前缀列的查询来说选择性也更高。然而性能不仅依赖于所有索引列的选择性,也和查询条件的具体值有关。这和选择前缀的长度需要考虑的地方一样。可能需要根据那些运行频率最高的查询来调整索引列的顺序,这种情况下索引的选择性最高。

3.3.5 聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。具体的细节依赖于其实现方式,InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引与数据行。

当表有聚簇索引时,它的数据行实际上存放在索引的叶子页中。术语“聚簇”表示数据行和相邻的键值紧凑地存储在一起。因为无法把数据行存放在不同的地方,所以一个表只能有一个聚簇索引。

因为是存储引擎负责实现索引,因此表示所有的存储引擎都支持聚簇索引。

3.3.6 覆盖索引

如果一个索引包含所有需要查询的字段的值,称之为“覆盖索引”。可以极大地提高性能:

索引条目通常远小于数据行大小,所以如果只需要读取索引,那MySQL就会极大地减少数据访问量。

因为索引时按照列值顺序存储的,所以对于I/O密集型的范围查询会比随机从磁盘读取每一行数据的I/O要少的多。

一些存储引擎只在内存中缓存索引,数据则依赖于操作系统来缓存,因此访问数据需要一次系统调用。

InnoDB有聚簇索引,对其特别有用。

3.3.7 使用索引扫描排序

MySQL有两种方式可以生成有序的结果:通过排序操作;或者按索引顺序扫描;如果EXPLAIN出来的type列的值为“index”,则说明MySQL使用了索引扫描来做排序。

3.3.8 压缩索引

MyISAM使用前缀压缩来减少索引的大小,从而让更多的索引可以放入内存中,这在某些情况下能极大地提高性能。默认只压缩字符串,但通过参数设置也可对整数做压缩。

3.3.9 冗余和重复索引

MySQL运行在相同的列上创建多个索引。需要单独维护重复的索引,并且优化器在优化查询的时候也需要逐个进行考虑,这会影响性能。

重复索引时指相同的列上按照相同的顺序创建的相同类型的索引。应避免这样创建重复索引,发现后也应立即移除。

3.3.10 未使用的索引

有一些服务器永远不用的索引,这样的索引完全是累赘,建议删除。

3.3.11 索引和锁

索引可以让查询锁定更少的行。如果你的查询从不访问那些不需要的行,那么就会锁定更少的行,从两方面看这对性能都有好处。首先,InnoDB虽然行锁效率很高,内存使用也很少,但是锁定行的时候仍会带来额外开销;其次,锁定超过需要的行会增加锁增用并减少并发性。

3.4 维护索引和表

即使用正确的类型创建了表并加上了合适的索引,还需要维护表和索引以确保它们能正常地工作。维护表有三个主要目的:找到并修复损坏的表;维护准确的索引统计信息;减少碎片。

3.4.1 找到并修复损坏的表

表损坏是很糟糕的事情。对于MyISAM,表损坏通常是系统崩溃导致的。其他的引擎也会由于硬件问题、MySQL本身的缺陷或者操作系统的问题导致索引损坏。

损坏的索引会导致查询返回错误的结果或者莫须有的主键冲突等问题,严重时还会导致数据库的崩溃。

可以使用REPAIR TABLE来修复表,但同样本身所有存储引擎都支持该命令。

3.4.2 更新索引统计信息

MySQL的查询优化器会通过两个API来了解存储引擎的索引值的分布信息,以决定如何使用索引。第一个API是record_in_range,通过向存储引擎传入两个边界值获取在这个范围大概有多少条记录。第二个API是info(),该接口返回各种类型的数据,包括索引的基数。

3.4.3 减少碎片

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

可以通过执行OPTIMIZE TABLE或者导出再导入的方式来重新整理数据。



你可能感兴趣的:(MySQL读书学习笔记)