mysql的索引剖析

mysql的索引剖析

一、索引简介

1、概念:索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址,在数据十分庞大的时候,索引可以大大加快查询的速度,这是因为使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据。索引需要占用磁盘空间,因此在创建索引时要考虑到磁盘空间是否足够,并且创建索引时需要对表加锁,因此实际操作中需要在业务空闲期间进行。

2、索引的优缺点

优势: 可以快速检索,减少I/O次数,加快检索速度;根据索引分组和排序,可以加快分组和排序;

劣势: 索引本身也是表,因此会占用存储空间,一般来说,索引表占用的空间的数据表的1.5倍;索引表的维护和创建需要时间成本,这个成本随着数据量增大而增大;构建索引会降低数据表的修改操作(删除,添加,修改)的效率,因为在修改数据表的同时还需要修改索引表。


二、B+树

在这里插入图片描述

1、B+树特点: B+Tree是BTree的一个变种,B+Tree和BTree的不同主要在于:

  1. B+Tree中的非叶子结点不存储数据,只存储key和指针;

  2. 所有键值都会出现在叶子结点上,叶子结点有一个链指针,方便区间范围查找;

  3. B+Tree的每个非叶子节点由n个键值key和n个指针point组成;

2、B+Tree对比BTree的优点:

1)、磁盘读写代价更低

一般来说B+Tree比BTree更适合实现外存的索引结构,因为存储引擎的设计专家巧妙的利用了外存(磁盘)的存储结构,即磁盘的最小存储单位是扇区(sector),而操作系统的块(block)通常是整数倍的sector,操作系统以页(page)为单位管理内存,一页(page)通常默认为4K,数据库的页通常设置为操作系统页的整数倍,因此索引结构的节点被设计为一个页的大小,然后利用外存的“预读取”原则,每次读取的时候,把整个节点的数据读取到内存中,然后在内存中查找,已知内存的读取速度是外存读取I/O速度的几百倍,那么提升查找速度的关键就在于尽可能少的磁盘I/O,那么可以知道,每个节点中的key个数越多,那么树的高度越小,需要I/O的次数越少,因此一般来说B+Tree比BTree更快,因为B+Tree的非叶节点中不存储data,b+树的中间节点不保存数据,所以磁盘页能容纳更多节点元素,更“矮胖”,就可以存储更多的key。

2)、查询速度更稳定

由于B+Tree非叶子节点不存储数据(data),因此所有的数据都要查询至叶子节点,而叶子节点的高度都是相同的,因此所有数据的查询速度都是一样的。
3)、易于区间的范围查找

很多存储引擎在B+Tree的基础上进行了优化,添加了指向相邻叶节点的指针,形成了带有顺序访问指针的B+Tree,这样做是为了提高区间查找的效率,只要找到第一个值那么就可以顺序的查找后面的值。


三、MyISAM 索引实现 底层索引的实现

简介:在索引的分类中,我们可以按照索引的键是否为主键来分为“主索引”和“辅助索引”,使用主键键值建立的索引称为“主索引”,其它的称为“辅助索引”。因此主索引只能有一个,辅助索引可以有很多个。

1、主索引:MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的 data 域存放的是数据记录的地址。下图是 MyISAM 主索引(Primary key)的原理图:可以看出 MyISAM 的索引文件仅仅保存数据记录的地址。
在这里插入图片描述

2、辅助索引

在 MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求 key 是唯一的,而辅助索引的 key 可以重复。同样也是一颗 B+Tree,data 域保存数据记录的地址。因此,MyISAM 中索引检索的算法为首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其data 域的值,然后以 data 域的值为地址,读取相应数据记录。
在这里插入图片描述

3、非聚集索引

MyISAM 的索引方式也叫做“非聚集索引”,非聚集(unclustered)索引:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。我们可以通过两次查询来找到所查找的结果,先找到目录中的结果地址,然后再通过地址找到数据行。我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”,MyISAM的索引方式索引和数据存放是分开的,非聚集的,所以也叫做非聚集索引。。


四、InnoDB 底层索引的实现

1、主索引:InnoDB 也使用 B+Tree 作为索引结构,但具体实现方式却与 MyISAM 截然不同。 InnoDB 的数据文件本身就是索引文件。 从上文知道,MyISAM 索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶点data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。

在这里插入图片描述

2、辅助索引: InnoDB 的辅助索引 data 域存储相应记录主键的值而不是地址。换句话说,InnoDB 的所有辅助索引都引用主键作为 data 域。辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。
在这里插入图片描述

3、聚集索引

由InnoDB 主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为 InnoDB 的数据文件本身要按主键聚集。聚集索引这种实现方式使得按主键的搜索十分高效。聚簇索引的数据是根据主键的顺序保存。因此适合按主键索引的区间查找,可以有更少的磁盘I/O,加快查询速度。但是也是因为这个原因,聚簇索引的插入顺序最好按照主键单调的顺序插入,否则会频繁的引起页分裂,严重影响性能。


四、联合索引及最左原则

1、概念: 两个或更多个列上的索引被称作联合索引,联合索引又叫复合索引。对于复合索引Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。在Mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先。

2、示例: 如果我们建立了一个2列的联合索引(col1,col2),实际上已经建立了两个联合索引(col1)、(col1,col2); 如果有一个3列索引(col1,col2,col3),实际上已经建立了三个联合索引(col1)、(col1,col2)、(col1,col2,col3)。


五、索引失效

索引失效的情况:

  • 在组合索引中不能有列的值为NULL,如果有,那么这一列对组合索引就是无效的。
  • LIKE操作中,like查询是以’%‘开头的不会使用索引,’%aaa%'不会使用索引,也就是索引会失效,但是‘aaa%’可以使用索引。
  • 在索引的列上使用表达式或者函数会使索引失效,例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate<’2007-01-01′。其它通配符同样,也就是说,在查询条件中使用正则表达式时,只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。
  • 在索引字段上使用not,<>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 优化方法: key<>0 改为 key>0 or key<0。
  • 字符串不加单引号会导致索引失效。更准确的说是类型不一致会导致失效,比如字段email是字符串类型的,使用WHERE email=99999 则会导致失败,应该改为WHERE email=‘99999’。
  • 在查询条件中使用OR连接多个条件会导致索引失效,除非OR链接的每个条件都加上索引,这时应该改为两次查询,然后用UNION ALL连接起来。
  • 联合索引中,where中索引列违背最左匹配原则,一定会导致索引失效

六、索引树的层数

假设:表的记录数是N、每一个BTREE节点平均有B个索引KEY、那么B+TREE索引树的高度就是logNB(等价于logN/logB)。

由于索引树每个节点的大小固定,所以索引KEY越小,B值就越大,那么每个B+TREE节点上可以保存更多的索引KEY,也就是B值越大,索引树的高度就越小,那么基于索引的查询的性能就越高。所以相同表记录数的情况下,索引KEY越小,索引树的高度就越小。

在计算机中磁盘存储数据最小单元是扇区,一个扇区的大小是512字节,而文件系统(例如XFS/EXT4)他的最小单元是块,一个块的大小是4k,而对于我们的InnoDB存储引擎也有自己的最小储存单元——页(Page),一个页的大小是16K。

1、通常一棵B+树可以存放多少行数据?

单个叶子节点(页)中的记录数=16K/1K=16。(这里假设一行记录的数据大小为1k,实际上现在很多互联网业务数据记录大小通常就是1K左右)。这里我们先假设B+树高为2,即存在一个根节点和若干个叶子节点,那么这棵B+树的存放总记录数为: 根节点指针数*单个叶子节点记录行数

上文我们已经说明单个叶子节点(页)中的记录数=16K/1K=16。(这里假设一行记录的数据大小为1k,实际上现在很多互联网业务数据记录大小通常就是1K左右)。

那么现在我们需要计算出非叶子节点能存放多少指针?

其实这也很好算,我们假设主键ID为bigint类型,长度为8字节,而指针大小在InnoDB源码中设置为6字节,这样一共14字节,我们一个页中能存放多少这样的单元,其实就代表有多少指针,即 16384/14=1170 。那么可以算出一棵高度为2的B+树,能存放 1170*16=18720 条这样的数据记录。

根据同样的原理我们可以算出一个高度为3的B+树可以存放: 1170*1170*16=21902400 条这样的记录。所以在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次IO操作即可查找到数据。一个千万量级,且存储引擎是MyISAM或者InnoDB的表,其索引树的高度在3~5层左右。

猜你喜欢

转载自blog.csdn.net/u014618114/article/details/107637071