如下图所示为一个页的结构,数据存储最小单元,mysql默认为16 kb。B+Tree中的一个叶子节点是一页。
所有InnoDB的索引是B树,其中索引记录被存储在树的树叶页。一个索引页的默认大小是16KB。当新记录被插入,InnoDB试着为将来索引记录的插入和更新留下十六分之一的空白页。
如果索引记录以连续的顺序被插入(升序或者降序),结果索引页大约是15/16满。如果记录被以随机的顺序被插入,页面是从1/2到 15/16满。如果索引页的填充因子降到低于1/2,InnoDB试着搜索索引树来释放页。

页结构图

图示说明: 1111a,分别表示col1,col2,col3,col4,col5 五列数据。红色标记为以主键构造的主键索引,也为聚簇索引。
用户数据区:数据为链表结构,对于链表结构而言,插入性能较高,而查询性较低,因此这个链表的长度不会很长,那么mysql是怎么解决这个问题的呢?当然是通过页目录来解决。
主键索引结构图

联合索引结构图

所以可以看到联合索引上只会存联合索引对应几个字段的数据,同时会存一个主键的值,当查询的数据不在索引树上时,进行回表操作。

MyISAM存储引擎实现

包含三个文件,分别是xxx.frm(表结构信息),xxx.MYD(表数据信息),xxx.MYI(表索引信息)

InnoDB存储引擎实现

包含两个文件,xxx.frm(表结构信息),xxx.ibd(数据和索引信息)

简单一句话回答就是,像MyISAM这样索引和数据文件是分开的,就叫非聚集索引。像InnoDB这样索引和数据在一起的就叫聚集索引。
注意:InnoDB也不是说所有的索引都是聚集索引,一般来说主键索引才是聚集索引,主键索引上存的数据是该行的其他列的所有数据。而不是主键索引的话记录的,一般存的的是对应这一行的主键,然后去主键索引中根据字段查找对应的数据,实际上也是一种回表操作。
因为InnoDB的数据,ibd文件是通过B+树来组织的,如果没有主键的话,无法构建这个文件。当然在自己没有建主键的情况下,mysql会依次去扫描你的每个列,如果其中有一列的数据是不重复的,则会将这一列默认当成主键列,如果实在没有,mysql会维护一个隐藏列作为主键,并确保该列数据不重复。