Innodb和MyISAM索引的区别
虽然说MyISAM和InnoDB都是使用了B+Tree
作为索引结构,但是它们两者在实现却有很大的差异。
作为面试中MySQL必不可少的一环节,本文就来简单介绍一下两者的区别。
# MyISAM索引实现
MyISAM引擎使用B+Tree
作为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图:
索引会按照顺序排列,以下 col1 索引的顺序和数据行的物理顺序一致~
这里设表一共有三列,假设我们以Col1
为主键,则上图是一个MyISAM表的主键索引(Primary key)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。
假如是普通索引呢?
在MyISAM中,主键索引和辅助索引(Secondary key,可以理解为普通索引)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。如果我们在Col2
上建立一个辅助索引,则此索引的结构如下图所示:
注意这里的第三列,索引的顺序和 Col2 的数据行的物理顺序不一致
索引是 5、22、34、77、89、91 排列,而Col2的物理行是无序的
同样也是一颗B+Tree,data域保存数据记录的地址。
因此,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。
MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。
# InnoDB索引实现
虽然InnoDB也使用B+Tree
作为索引结构,但具体实现方式却与MyISAM截然不同。
第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。
上图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。
第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。例如,下图为定义在Col3上的一个辅助索引:
这里以英文字符的ASCII码作为比较准则。聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。(又称为 回表)
了解不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助,例如知道了InnoDB的索引实现后,就很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。
再例如,用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。
# 总结
MyISAM是非聚簇索引,叶子副本上存储的物理空间地址,而物理空间地址是混乱无序的,MyISAM只能先取数据,再排序
InnoDB是聚簇索引,叶子子系统是双向链表,也就是物理放置顺序和索引顺序一致,在相邻的双向链表取数据的同时,完成了ORDER BY PRIMARY
排序工作
所以我们可以区分这两种索引:
这也是面试常问的
聚簇索引:聚集(clustered)索引,也叫聚簇索引。
定义:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。
就像一本字典一样,汉字通过A—Z排列,比如说查找一个**“中”字,我们通过字典的目录,就可以找到对应的页码;如果要插入一个“啊”字,那么它必然要插入到“中”**字前面。
地址 | id | username | score |
---|---|---|---|
0x01 | 1 | 小明 | 90 |
0x02 | 2 | 小红 | 80 |
0x03 | 3 | 小华 | 92 |
.. | .. | .. | .. |
0xff | 256 | 小英 | 70 |
注:第一列的地址表示该行数据在磁盘中的物理地址,后面三列才是我们SQL里面用的表里的列,其中id是主键,建立了聚集索引。
数据行的物理顺序与列值的顺序相同,如果我们查询id比较靠后的数据,那么这行数据的地址在磁盘中的物理地址也会比较靠后。而且由于物理排列方式与聚集索引的顺序相同,所以也就只能建立一个聚集索引了。
非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因。
# 两者使用场景:
MyISAM | InnoDB | |
---|---|---|
事务 | 非事务安全 | 事务安全 |
锁的粒度 | 表级 | 行级 |
FULLTEXT(全文类型)索引 | 不支持 | 支持 |
安全 | 较安全,支持redolog | |
存储 |
MyISAM相对简单,所以在效率上要优于InnoDB,小型应用可以考虑使用MyISAM。
由于锁的粒度,频繁更新的表适合使用innodb,而且支持事务;如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。