InnoDB-聚簇索引和MyISAM非聚簇索引

概述:聚簇索引并不是一种单纯的索引类型,而是一种数据存储方式。因为是存储引擎负责实现索引,因此不是所有的存储引擎都支持聚簇索引(如MyISAM)。如:InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。

术语:“聚簇”表示数据行和相邻的键值紧凑的存储在一起。因为无法同时把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引(不过,覆盖索引可以模拟多个聚簇索引的情况)。

当表有聚簇索引时,它的数据行实际上存放在索引的叶子页(leaf page)中。

下图为聚簇索引存放展示:叶子页包含了行的全部数据,但是节点页只包含了索引列(图示中索引列包含的是整数值/主键)

InnoDB-聚簇索引和MyISAM非聚簇索引

 MyISAM为非聚簇索引,需要独立的行存储(一张表存储到磁盘时三个文件:.frm\.MYD\.MYI),每一个叶子页节点存储的是已经排序的列值(索引列),以及列值对应的行号。

如下图。注意:MyISAM是按照数据插入的书记徐存储数据,大部分情况如行是定长的,行号按插入顺序排列(从0开始)

InnoDB-聚簇索引和MyISAM非聚簇索引

 InnoDB中,聚簇索引“就是”表,不像MyISAM那样需要独立的行存储(.frm一个文件);聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行

InnoDB-聚簇索引和MyISAM非聚簇索引

但是当主键不是AUTO_INCREMENT时,数据行插入时,是按主键值的大小去排列的,这就会造成如下后果:

(1)、当插入一条数据之前,需要为该条数据寻找合适的位置—通常是已有数据的中间位置—并且分配空间,而已有数据已经刷到磁盘上并从缓存中移除,或还没有加载到缓存中,InnoDB不得不先找到并从磁盘读取目标页到内存中,造成磁盘大量的随机I/O

(2)、因为写入是乱序的,InnoDB不得不频繁的做页分裂操作(如果是自增,则不分页,此页满,进入下一页即可),导致移动大量数据,一次插入最少需要修改三个页面而不是一个页面

(3)、频繁的页分裂,页会变得稀疏并被不规则的填充,所以最终数据会有碎片

下图为向一张用户表(主键自增/非自增)对比图,表字段大概有17个(如姓名、邮箱、电话、简介等。。。)

InnoDB-聚簇索引和MyISAM非聚簇索引

InnoDB的二级索引和聚簇索引很不相同。二级索引叶子节点中存储的不是“行指针”,而是主键值,并以此作为指向行的“指针”。

下图为InnoDB和MyISAM保存数据的区别

InnoDB-聚簇索引和MyISAM非聚簇索引

PS:本文章内容和图片均参考书籍《高性能MySQL》第三版,电子工业出版社