MyISAM和InnoDB是MySQL最经常使用的两个存储引擎,本文将进行详尽的介绍和对比。对于MySQL其他几种存储引擎,请读者自行搜索学习。mysql
本文会图解两种引擎的索引结构区别,而后讲解索引的原理,理解本文内容,就可以理解索引优化的各类原则的背后缘由。算法
限于篇幅,本篇没有介绍的知识,会在后续博客将逐一讲解。例如:MySQL引擎的锁机制、多列索引的生效规则、索引优化等主题。sql
下面SQL在本篇介绍引擎的结构区别时使用的表结构,便于读者更好理解。数据库
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '惟一码',
`age` int(5) NOT NULL COMMENT '年龄',
`name` varchar(5) NOT NULL COMMENT '名字',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=92 DEFAULT CHARSET=utf8mb4;
复制代码
B-树、B树和B-tree是同一个数据结构,只不过英语翻译过来以后,有些人误解了觉得是多种树。因此好多讲解树的数据结构的博客彻底是误导初学者。。。请读者认真分辨。缓存
MyISAM和InnoDB的索引均采用B+树数据结构,因此接下来先介绍一下B树与B+树。安全
B树是一种多路搜索树。bash
下图是一个M=4阶的B树。数据结构
B树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,若是命中则结束,不然进入查询关键字所属范围的儿子结点;重复,直到所对应的是叶子结点。并发
查找文件29的过程:nosql
B树的特性:
下图是一个M=3阶的B+树。
通常在数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增长了顺序访问指针。
B+树是B树的一种变形树,总结起来,数据库索引的B+树与B树的差别在于:
B+树的特性:
解释这个问题以前,须要了解一些基础知识。
因为存储介质的特性,磁盘自己存取就比主存慢不少,再加上机械运动耗费,磁盘的存取速度每每是主存的几百分之一,所以为了提升效率,要尽可能减小磁盘I/O。为了达到这个目的,磁盘每每不是严格按需读取,而是每次都会预读,即便只须要一个字节,磁盘也会从这个位置开始,顺序向后读取必定长度的数据放入内存。这样作的理论依据是计算机科学中著名的局部性原理:
当一个数据被用到时,其附近的数据也一般会立刻被使用——程序运行期间所须要的数据一般比较集中。
因为磁盘顺序读取的效率很高(不须要寻道时间,只需不多的旋转时间),所以对于具备局部性的程序来讲,预读能够提升I/O效率。
预读的长度通常为页的整倍数。页是计算机管理存储器的逻辑块,硬件及操做系统每每将主存和磁盘存储区分割为连续的大小相等的块,每一个存储块称为一页(在许多操做系统中,页得大小一般为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,而后异常返回,程序继续运行。
通常来讲,磁盘I/O次数能够用于评价索引结构的优劣。在B-Tree中查找,可知检索一次最多须要访问h个节点(上文举例查找文件29的过程)。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每一个节点只须要一次I/O就能够彻底载入。
为了达到这个目的,在实际实现中,B树还使用以下技巧:
综上所述,用B树做为索引结构效率是很是高的。
红黑树或者平衡二叉树的其余树结构,
因此其余树结构的效率明显比B树差不少。
笔者认为第三条缘由才是MySQL使用B+树而不是B树作索引的主要缘由,毕竟MongoDB的索引是B树,因此两种数据结构并无绝对的好坏,要看实际的业务需求。
MyISAM在磁盘存储上有三个文件,每一个文件名以表名开头,扩展名指出文件类型。
MyISAM引擎使用B+树做为索引结果,叶节点的data域存放的是数据记录的地址。
MyISAM索引文件和数据文件是分离的,索引文件仅保存记录所在页的指针(物理位置),经过这些地址来读取页,进而读取被索引的行。
树中叶子保存的是对应行的物理位置。经过该值,存储引擎能顺利地进行回表查询,获得一行完整记录。同时,每一个叶子页也保存了指向下一个叶子页的指针。从而方便叶子节点的范围遍历。
在MyISAM中,主键索引和辅助索引在结构上没有任何区别,只是主键索引要求key是惟一的,而辅助索引的key能够重复。
MySQL5.5开始支持InnoDB引擎,并将其做为默认数据库引擎。
Innodb有两种存储方式,共享表空间存储和多表空间存储。
Innodb只有表结构文件和数据文件。
表结构文件和MyISAM同样,以表名开头,扩展名是.frm。
数据文件与存储方式有关:
Innodb主键索引中,既存储了主键值,又存储了行数据。
对于辅助索引,InnoDB采用的方式是在叶子页中保存主键值,经过这个主键值来回表(上图)查询到一条完整记录,所以按辅助索引检索实际上进行了二次查询,效率确定是没有按照主键检索高的。
MyISAM存储表分为三个文件frm(表结构)、MYD(表数据)、MYI(表索引),而Innodb如上文所说,根据存储方式不一样,存储结构不一样。
MyISAM不支持事务,而Innodb支持事务,具备事务、回滚和恢复的事务安全。
MyISAM不支持外键,而Innodb支持外键。MyISAM容许没有主键,可是Innodb必须有主键,若未指定主键,会自动生成长度为6字节的主键。
MyISAM只支持表级锁,而Innodb支持行级锁,具备比较好的并发性能,可是行级锁只有在where子句是对主键筛选才生效,非主键where会锁全表
MyISAM使用B+树做为索引结构,叶节点保存的是存储数据的地址,主键索引key值惟一,辅助索引key能够重复,两者在结构上相同。Innodb也是用B+树做为索引结构,数据表自己就是按照b+树组织,叶节点key值为数据记录的主键,data域为完整的数据记录,辅助索引data域保存的是数据记录的主键。
MongoDB不是传统的关系性数据库,而是以Json格式做为存储的nosql,目的就是高性能,高可用,易扩展。首先它摆脱了关系模型,因此范围查询和遍历查询的需求就没那么强烈了,其次Mysql因为使用B+树,数据都在叶节点上,每次查询都须要访问到叶节点,而MongoDB使用B-树,全部节点都有Data域,只要找到指定索引就能够进行访问。
整体来讲,Mysql选用B+树和MongoDB选用B-树仍是以本身的需求来选择的。
用表中的普通列构建的索引,没有任何限制
惟一索引列的值必须惟一,但容许有空值。若是是组合索引,则列值的组合必须惟一。
根据主键创建索引,不容许重复,不容许空值;
仅可用于MyISAM表,针对较大的数据,生成全文索引很是的消耗时间和空间(在生成FULLTEXT索引时,会为文本生成一份单词的清单,在索引时及根据这个单词的清单来索引)。
又叫联合索引。用多个列组合构建的索引,这多个列中的值不容许有空值。能够在建立表的时候指定,也能够修改表结构。
ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');
为了更多的提升mysql效率可创建组合索引,遵循”最左前缀“原则。建立复合索引时应该将最经常使用(频率)做限制条件的列放在最左边,依次递减。示例的组合索引至关于创建了col1,col1col2,col1col2col3三个索引,而col2或者col3是不能使用索引的。
假设联合索引由列(a,b,c)组成,则一下顺序知足最左前缀规则:a、ab、abc;selece、where、order by 、group by均可以匹配最左前缀。其它状况都不知足最左前缀规则就不会用到联合索引。
定义:数据行的物理顺序与列值(通常是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个汇集索引。
若是定义了主键,Innodb会选择主键做为汇集索引;若是没有定义主键,Innodb会选择不包含NULL值的惟一索引做为汇集索引;若是也没有这样的惟一索引列,Innodb会选择内置6字节长的rowID做为隐含的汇集索引,这里的RowId会随着记录的写入而主键自增,可是它是不可引用和查看的,是数据库引擎内部的使用。
若是咱们使用自增主键,那么每次插入的新纪录都在原先记录的尾部按照顺序,添加到当前节点的索引后面,当一页快写满的时候,就会开辟一个新的页。数据记录自己就存与主索引的叶子节点上,B+tree的树。这就要求每个叶子节点内的各条数据记录按主键顺序存放,所以每当有一条新的记录插入的时候,MYSQL会根据其主键将其插入到合适的节点和位置上,若是页面达到装载因子(INNODB默认为15/16),则开辟新的页面(节点)
若是使用非自增主键(若是身份证号或学号等),因为每次插入主键的值近似于随机,所以每次新纪录都要被插到现有索引页得中间某个位置,此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增长了不少开销,同时频繁的移动、分页操做形成了大量的碎片,获得了不够紧凑的索引结构,后续不得不经过OPTIMIZE TABLE来重建表并优化填充页面。
定义:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不一样,一个表中能够拥有多个非汇集索引。
除了InnoDB的主键索引,在mysql中的其余索引形式都是非汇集索引。
指从辅助索引中就能获取到须要的记录,而不须要查找主键索引中的记录。使用覆盖索引的一个好处是由于辅助索引不包括一条记录的整行信息,因此数据量较汇集索引要少,能够减小大量io操做。