5.1 索引基础
索引是存储引擎快速找到记录的一种数据结构,因为在引擎层,所以没有统一的标准。
如果没有特别说明,一般的索引指B-Tree索引,InnoDB用的B+树
不需要全表扫描,而是从索引根节点开始搜索。
根节点的槽中存放指向子节点的指针。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。
叶子节点比较特别,他们的指针指向的是被索引的数据,而不是其他的节点页。
树的深度和表的大小直接相关。
前面所述的索引树对如下类型的查询有效
下面是B-Tree索引的限制:
哈希索引
基于哈希表实现,只有精确匹配索引所有列的查询才有效。
对于每一行数据,存储引擎会对所有的索引列计算一个哈希码(代表对象的特征,同一个类的对象按照自己的不同特征尽量有不同的哈希码)。哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存在索引中,同时在哈希表中保存指向每个数据行的指针。
在MySQL中,只有Memory引擎显示支持哈希索引。它同时支持B-Tree索引。值得一提的是,它支持非唯一哈希索引。
先计算Peter的哈希码,然后找value即指向第N行的指针,最后判断第N行值是否为Peter
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 索引的优点
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 聚簇索引
不是一种单独的索引类型,而是一种数据存储方式。它的数据行存放在索引的叶子页中。聚簇表示数据行和相邻的键值紧凑地存储在一起。因为数据行不能放在两个地方,所以一个表只能有一个聚簇索引。
因为是存储引擎负责索引,不是所有的存储引擎都支持聚簇索引。
索引列包含了整数值,叶子页包含了行的全部数据。
如果没有定义主键,InnoDB会选择一个唯一的非空索引作主键,如果没有这样的索引,InnoDB会隐式定义一个主键作聚簇索引
优点:
缺点:
5.3.6 覆盖索引
如果一个索引包含所有需要查询的字段的值(索引列的值),称它为覆盖索引
优点:
MySQL不能在索引中执行LIKE操作
查询只能使用索引的最左前列,直到遇到第一个范围查询为止
随着偏移量的增加,MySQL花大量时间扫描已放弃的数据,反范式化,预先计算和缓存是唯一的办法。
另一种是延迟关联。使用覆盖索引查询返回需要的主键。再通过主键关联原表获得需要的行。