Mysql的索引
3.1.1.索引简介
为了满足对数据的快速访问,我们通常需要将数据组织成一种有序的方式, 而原始的情况下数据的物理存储顺序便可代表一种“序”,但是由于物理存储的“序”只能是一种,但我们业务的访问模式是多样的,所以我们有了索引,索引是一种以更小代价来组织数据关系的一种“序”,不同的索引可以满足不同的访问模式。
索引类型的选择主要取决于应用的不同需求:
1、hash index主要用于满足精确匹配;
2、B-Tree index主要用于满足范围查询、精确匹配;
3、fulltext index主要用于全文关键字查询;
不同的存储引擎支持不同的索引类型:
1.heap引擎支持 hash index;
2.MyISAM 、InnoDB引擎支持B-Tree index;
3.MyISAM 支持fulltext index;
索引具体由存储引擎提供支持,而非MySQL内核,所以使用的是对同一种索引类型,内部的实现方式与效率都可能不同。
3.1.2.B-Tree
指B-Tree索引,它通常使用B-Tree数据结构来保存数据。大部分MySQL的存储引擎都支持B-Tree索引(Archive例外)。
B-Tree索引加速了数据访问。从B-Tree根开始,借助中间节点页的上界和下界值,可以快速搜寻到叶子页层,最终找到含有需要找的值的叶子页(或者确定无法找到需要的数据),找到对应的叶子页后可以通过相应的指针直接找到数据表中对应的数据行。这样存储引擎不会扫描整个表得到需要的数据。同时B-Tree索引通常意味着索引中数据保存时有序的,可以利用B-Tree索引来加速排序。
3.1.2.1. InnoDB B-Tree
存储引擎使用了不同的方式把B-Tree索引保存到磁盘上,它们会表现出不同的性能。例如MyISAM使用前缀压缩的方式以减小索引;
而InnoDB不会压缩索引。
同时MyISAM的B-Tree索引按照行存储的物理位置来引用被索引的行,但是InnoDB按照主键值引用行。这些不同有各自的优点和缺点。
3.1.2.1.1.InnoDB聚簇索引(cluster index)
聚簇索引不是一种单独的索引类型,而是一种存储数据的方式。当表有聚簇索引的时候,它的数据行实际保存在索引的叶子页。聚簇是指实际的数据行和相关的键值都保存在一起。每个表只能有一个聚簇索引。
由于是存储引擎负责实现索引,并不是所有的存储引擎都支持聚簇索引。当前只有SolidDB和InnoDB是唯一支持聚簇索引的存储引擎。
数据与索引在同一个B-Tree上,一般数据的存储顺序与索引的顺序一致。InnoDB cluster index每个叶子节点包含primary key 和行数据,非叶子节点只包括被索引列的索引信息。
聚簇索引的优缺点:
优点:
1.相关的数据保存在一起,利于磁盘存取;
2.数据访问快,因为聚簇索引把索引和数据一起存放;
3.覆盖索引可以使用叶子节点的primary key的值使查询更快;
缺点:
1.如果访问模式与存储顺序无关,则聚簇索引没有太大的用处;
2.按主键顺序插入和读取最快, 但是如果按主键随机插入(特别是字符串)则读写效率降低;
3.更新聚簇索引的代价较大,因为它强制InnoDB把每个更新的行移到新的位置;
4.建立在聚簇索引上的表在插入新行,或者在行的主键被更新,该行必须被移动的时候会进行分页。分页发生在行的键值要求行必须被放到一个已经放满了数据的页的时候,此时存储引擎必须分页才能容纳该行,分页会导致表占用更多的磁盘空间。
5.聚簇表可能会比全表扫描慢,尤其在表存储的比较稀疏或因为分页而没有顺序存储的时候。
6.非聚簇索引可能会比预想的大,因为它们的叶子节点包含了被引用行的主键列。
7.非聚簇索引访问需要两次索引查找,而不是一次。
其它需要说明点:
InnoDB的primary key为cluster index,
除此之外,不能通过其他方式指定cluster index,
如果InnoDB不指定primary key,InnoDB会找一个unique not null 的field做cluster index,
如果还没有这样的字段,则InnoDB会建一个非可见的系统默认的主键---row_id(6个字节长)作为cluster_index 。
建议使用数字型auto_increment 的字段作为 cluster index 。
不推荐用字符串字段做cluster index (primary key) , 因为字符串往往都较长, 会导致secondary index过大(secondary index的叶子节点存储了primary key 的值),而且字符串往往是乱序。
cluster index乱序插入容易造成插入和查询的效率低下。
3.1.2.1.2.InnoDB辅助索引(secondary index)
InnoDB 中非cluster index的所有索引都是secondary index。
secondary index的查询代价变大,需要两次B-Tree查询,一次secondary index, 一次cluster index。
所以在建立cluster index和secondary index的时候需要考虑到这点。
当secondary index满足covering index(参见3.1.2.1.4章节介绍)时,只需要一次B-Tree查询并且直接在secondary index便可获取所需数据,不需要再进行数据读取,提高了效率。我们在设计索引和写SQL语句的时候就可以考虑利用到covering index的优势。
建议尽量减少对 primary key 的更新, 因为secondary index叶子节点包含primary key 的value (这样避免当row被移动或page split时更新secondary index), primary key的变化会导致所有secondary index的更新。
3.1.2.1.3.InnoDB动态哈希(adaptive hash index)
动态哈希索引是InnoDB为了加速B-Tree上的节点查找而保存的hash表 。 B-Tree上经常被访问的节点将会被放在动态哈希索引中。
注意点:
MySQL重启后的速度肯定会比重启前慢, 因为InnoDB的innodb_buff_pool和adaptive hash index都是内存型的,重启后消失,需要预热(访问一段时间) 后性能才能慢慢上来。
3.1.2.1.4.InnoDB覆盖索引(covering index)
索引通常是用于找到行的,但也可以用于找到某个字段的值而不需要读取整个行,因为索引中存储了被索引字段的值,只读索引不读数据, 这种情况下的索引就叫做覆盖索引。
覆盖索引是很有力的工具,可以极大地提高性能。它主要的优势如下:
1.索引记录通常远小于全行大小,因此只读索引,MySQL就能极大的减少数据访问量。这对缓存的负载是非常重要的,它大部分的响应时间都花在拷贝数据上。对于I/O密集型的负载也有帮助。因为索引比数据小很多,能很好的装入内存。
2.索引是按照索引值来进行排序的,因此I/O密集型范围访问将会比随机地从磁盘提取每行数据要快的多。
3.覆盖索引对于InnoDB来说非常有用,因为InnoDB的聚集缓存。InnoDB的辅助索引在叶子节点保存了主键值,因此,覆盖了查询的第二索引在主键上避免了另外一次索引查找。
3.1.2.2. MyISAM B-Tree
&nb