1、为什么使用索引
索引是存储引擎用于快速找到数据记录的一种数据结构,好比一本教科书的目录部分,通过目录中找到对应文章的页码,便可快速定位到需要的文章。MySQL也是一样的道理,进行数据查找时,首先查看查询条件是否命中某条索引,符合则通过索引查找相关数据,如果不符合则需要全表扫描,即需要一条一条地查找记录,知道找到与条件符合的记录。
数据库没有索引的情况下,数据分布在硬盘不同的位置上面,读取数据时,摆臂需要前后摆动查找数据,操作非常消耗时间。如果数据顺序摆放,那么也需要从1到6行按顺序读取,相当于进行6次IO操作,依旧非常耗时。 如果我们不借助任何索引结构1帮助我们快速定位数据的话,我们查找col2=89这条记录,就要逐行去查找、去比较。从col2=34开始,进行比较,发现不是,继续下一行。我们当前的表只有不到10行数据,但如果表很大的话,有上千万条数据,就意味着要做很多很多次磁盘I/O才能找到。现在要查找col2=89这条记录,cpu必须先去磁盘查找这条记录,找到之后加载到内存,再对数据进行处理。这个过程最耗时间的就是磁盘IO(涉及到磁盘的旋转时间(速度较快)+磁头的寻道时间(速度慢+费时))。
假如给数据使用二叉树这样的数据结构进行存储,如下图所示:
对字段col2添加索引,相当于在硬盘上为col2维护了一个索引的数据结构,即二叉搜索树。二叉搜索树的每个结点存储的是**(K,V)结构**,key是col2,value是该key所在行的文件指针(地址)。比如:该二叉搜索树的根节点就是(34,0x07)。现在对col2添加了索引,这时再去查找col2=89这条记录的时候会先去查找该二叉搜索树(二叉树的遍历查找)。读34到内存,89>34;继续右侧数据,读89到内存,89==89;找到数据返回。找到之后的根据就是当前结点的value快速定位到要查找的记录对应的地址。我们可以发现,只需要查找两次就可以定位到记录的地址,查询速度就提高了。
建索引的目的:减少磁盘IO的次数,加快查询速率。
2、索引及其优缺点
MYSQL官方对索引的定义为:索引(Index)是帮助MySQL高速获取数据的数据结构。
索引的本质:索引是数据结构。你可以简单理解为“排好序的快速查找数据结构”,满足特定查找算法。这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法。
索引是在存储引擎中实现的,因此每种存储引擎的索引不一定完全相同,并且每种存储引擎不一定支持所有索引类型。同时,存储引擎可以定义每个表的最大索引数和最大索引长度。所有存储引擎支持每个表至少16个索引,总索引长度至少为256字节。有些存储引擎支持更多的索引数和更大的索引长度。
优点
- 类似大学图书馆建书目索引,提高数据检索的效率,降低数据库的IO成本,这也是创建索引最主要的原因
- 通过创建唯一索引,可以保证数据库中每一行数据的唯一性
- 在实现数据的参考完整性方面,可以加速表和表之间的连接。对于有依赖关系的子表和父表联合查询时,可以提高查询速度
- 在使用分组和排序子句进行数据查询时,可以显著减少查询中分组和排序的时间,降低CPU的消耗。
缺点
- 创建索引和维护索引要耗费时间,并且随着数据量的增加,所耗费的时间也会增加
- 索引需要占磁盘空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,存储在磁盘上,如果有大量的索引,索引文件就可能比数据文件更快达到最大文件尺寸。
- 虽然索引大大提高了查询速度,同时也会降低更新表的速度。当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据地维护速度。
3、InnoDB中索引的推演
3.1索引之前的查找
先来看一个精准匹配的例子:
select [列名列表] FROM 表名 WHERE 列名=xxx;
(1)在一个页中的查找
假设目前表中的记录比较少,所有的记录都可以被存放到一个页中,在查找记录的时候可以根据搜索条件的不同分为两种情况:
- 以主键为搜索条件
可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录 - 以其他列作为搜索条件
因为在数据页中并没有对非主键列建立所谓的页目录,所以我们无法通过二分法快速定位相应的槽。这种情况下只能从最小记录开始依次遍历单链表中的每条记录,然后对比每条记录是不是符合搜索条件。很显然,这种查找的效率是非常低的。
(2)在很多页中查找
大部分情况下我们表中存放的记录都是非常多的,需要好多的数据页来存储这些记录。在很多页中查找记录的话可以分为两个步骤:
- 定位到记录所在的页
- 从所在的页内中查找相应的记录
在没有索引的情况下,不论是根据主键列或者其他列的值进行查找,由于我们并不能快速的定位到记录所在的页,所以只能从第一个页沿着双向链表一直往下找,在每一个页中根据我们上面的查找方式去查找指定的记录。因为要遍历所有的数据页,所以这种方式显然是超级耗时的。如果一个表有一亿条记录呢?此时索引应运而生。
3.2设计索引
建一个表:
CREATE TABLE index_demo(
c1 INT,
c2 INT,
C3 CHAR(1),
PRIMARY KEY(C1)
)ROW_FORMAT=Compact;
(1)一个简单的索引设计方案
4、InnoDB中的索引方案
5、常见索引概念