MySQL存储引擎MyISAM和InnoDB,索引结构优缺点

MySQL存储引擎MyISAM和InnoDB底层索引结构算法

深刻理解MySQL索引底层数据结构与算法 (各类索引结构优缺点)数据库

Myisam和Innodb索引实现的不一样(存储结构)数据结构

存储引擎做用于什么对象

存储引擎是做用在表上的,而不是数据库。优化

MyISAM和InnoDB对索引和数据的存储在磁盘上是如何体现的

先来看下面建立的两张表信息,role表使用的存储引擎是MyISAM,而user使用的是InnoDB:spa

再来看下两张表在磁盘中的索引文件和数据文件:.net

1. role表有三个文件,对应以下:设计

role.frm:表结构文件
role.MYD:数据文件(MyISAM Data)
role.MYI:索引文件(MyISAM Index)指针


2. user表有两个文件,对应以下:对象

user.frm:表结构文件
user.ibd:索引和数据文件(InnoDB Data)
也因为两种引擎对索引和数据的存储方式的不一样,咱们也称MyISAM的索引为非汇集索引,InnoDB的索引为汇集索引。blog

InnoDB 索引文件和数据文件是一个;MyISAM索引文件和数据文件是分开的。

MyISAM主键索引与辅助索引的结构

咱们先列举一部分数据出来分析,以下:

上面已经说明了MyISAM引擎的索引文件和数据文件是分离的,咱们接着看一下下面两种索引结构异同。

主键索引

上一篇文章已经介绍过数据库索引是采用B+Tree存储,而且只在叶子节点存储数据,在MyISAM引擎中叶子结点存储的数据实际上是索引和数据的文件指针两类。

以下图中咱们以Col1列做为主键创建索引,对应的叶子结点储存形式能够看一下表格。

过索引查找数据的流程:先从索引文件中查找到索引节点,从中拿到数据的文件指针,再到数据文件中经过文件指针定位了具体的数据。

辅助(非主键)索引

以Col2列创建索引,获得的辅助索引结构跟上面的主键索引的结构是相同的。

在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是惟一的,而辅助索引的key能够重复。

InnoDB主键索引与辅助索引的结构

虽然InnoDB也使用B+Tree做为索引结构,但具体实现方式却与MyISAM大相径庭。

第一个重大区别是InnoDB的数据文件自己就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地 址。而在InnoDB中,表数据文件自己就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据 表的主键,所以InnoDB表数据文件自己就是主索引。

主键索引

咱们已经知道InnoDB索引是汇集索引,它的索引和数据是存入同一个.idb文件中的,所以它的索引结构是在同一个树节点中同时存放索引和数据,以下图中最底层的叶子节点有三行数据,对应于数据表中的Col一、Col二、Col3数据项。

上图是InnoDB主索引(同时也是数据文件)的示意图,能够看到叶节点包含了完整的数据记录。这种索引叫作汇集索引。由于InnoDB的数据文件自己要按主键汇集,因此InnoDB要求表必须有主键(MyISAM能够没有),若是没有显式指定,则MySQL系统会自动选择一个能够惟一标识数据记录的列做为主键,若是不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段做为主键,这个字段长度为6个字节,类型为长整形。

辅助(非主键)索引

第二个与MyISAM索引的不一样是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的全部辅助索引都引用主键做为data域。下图为定义在Col3上的一个辅助索引:

在最底层的叶子结点有两行数据,第一行的字符串是辅助索引,按照ASCII码进行排序,第二行的整数是主键的值。

这里以英文字符的ASCII码做为比较准则。汇集索引这种实现方式使得按主键的搜索十分高效,可是辅助索引搜索须要检索两遍索引:首先检索辅助索引得到主键,而后用主键到主索引中检索得到记录。

InnoDB索引结构须要注意的点

1. 数据文件自己就是索引文件

2. 表数据文件自己就是按B+Tree组织的一个索引结构文件

3. 汇集索引中叶节点包含了完整的数据记录

4. InnoDB表必需要有主键,而且推荐使用整型自增主键

正如咱们上面介绍InnoDB存储结构,索引与数据是共同存储的,不论是主键索引仍是辅助索引,在查找时都是经过先查找到索引节点才能拿到相对应的数据,若是咱们在设计表结构时没有显式指定索引列的话,MySQL会从表中选择数据不重复的列创建索引,若是没有符合的列,则MySQL自动为InnoDB表生成一个隐含字段做为主键,而且这个字段长度为6个字节,类型为整型。

 

那为何推荐使用整型自增主键而不是选择UUID?

UUID是字符串,比整型消耗更多的存储空间;
在B+树中进行查找时须要跟通过的节点值比较大小,整型数据的比较运算比字符串更快速;
自增的整型索引在磁盘中会连续存储,在读取一页数据时也是连续;UUID是随机产生的,读取的上下两行数据存储是分散的,不适合执行where id > 5 && id < 20的条件查询语句。
在插入或删除数据时,整型自增主键会在叶子结点的末尾创建新的叶子节点,不会破坏左侧子树的结构;UUID主键很容易出现这样的状况,B+树为了维持自身的特性,有可能会进行结构的重构,消耗更多的时间。

为何非主键索引结构叶子节点存储的是主键值?

保证数据一致性和节省存储空间,能够这么理解:商城系统订单表会存储一个用户ID做为关联外键,而不推荐存储完整的用户信息,由于当咱们用户表中的信息(真是名称、手机号、收货地址···)修改后,不须要再次维护订单表的用户数据,同时也节省了存储空间。

总结

了解不一样存储引擎的索引实现方式对于正确使用和优化索引都很是有帮助,例如知道了InnoDB的索引实现后,就很容易明白为何不建议使用过长 的字段做为主键,由于全部辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段做为主键在InnoDB中不是个好主意,由于 InnoDB数据文件自己是一颗B+Tree,非单调的主键会形成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用 自增字段做为主键则是一个很好的选择。

相关文章
相关标签/搜索