MySQL5:MySQL数据存储文件;MylSAM中索引和数据是两个独立的文件,它是如何通过索引找到数据呢?聚集索引/聚簇索引,InnoDB中二级索引为什么不存地址而是存键值?row ID如何理解?
MySQL是一个支持插件式存储引擎的数据库。在MySQL里面,每个表在创建的时候都可以指定它所使用的存储引擎。
主要关注一下最常用的两个存储引擎,MylSAM和InnoDB的索引的实现。
MySQL数据存储文件
MySQL的数据都是文件的形式存放在磁盘中的,MySQL数据库文件的位置是由datadir参数决定的,这些位置可能因具体的MySQL版本和安装方式而有所不同,用户也可以通过MySQL的配置文件(my.cnf)来设置MySQL数据库文件的位置。
下面命令可以查看到数据文件存储的位置
show global variables like 'datadir%';
我这里用的是Windows的
可以看到,在Windows系统中,数据文件是在C:\ProgramData\MySQL\MySQL Server 5.7\Data
在MySQL的数据目录下,每个数据库对应一个文件夹,对应数据库的表文件就存在对应命名的文件夹中,以test数据库为例,点击进入该文件夹,可以发现数据表文件
在这里我们能看到,每张InnoDB的表有两个文件(.frm和.ibd),MylSAM的表
有三个文件(.frm、.MYD、.MYI)。
数据文件:
- .frm文件:是表结构定义文件,它存储了表的元数据信息,包括表的字段、索引等。.frm是MySQL里面表结构定义的文件,不管你建表的时候选用任何一个存储引擎都会生成。
- .MYD文件:是数据文件,它存储了实际的表数据。
- .MYI文件:是索引文件,它存储了表的索引信息,用于加快查询速度。
.frm文件是表结构定义文件,它存储了表的元数据信息,包括表的字段、索引等。.frm是MySQL里面表结构定义的文件,不管你建表的时候选用任何一个存储引擎都会生成。我们主要看一下其他两个文件是如何实现MySQL不同的存储引擎的索引的。
MySQL中不同存储引擎索引落地方式
MylSAM
在MylSAM里面,另外有两个文件:
- .MYD文件:D代表Data,是MylSAM的数据文件。存放实际的表数据记录,比如stu_myisam.MYD表的所有的表数据。
- .MYI文件:I代表Index,是MylSAM的索引文件。存放索引,比如我们在id字段上面创建了一个主键索引,那么主键索引就是在这个索引文件里面。一个索引就会有一棵B+Tree,所有的B+Tree都在这个.MYI文件里面。
MylSAM中索引和数据是两个独立的文件,它是如何通过索引找到数据呢?
MylSAM的B+Tree里面,叶子节点存储的是数据文件对应的磁盘地址。所以从索引文件.MYI中找到键值后,会到数据文件.MYD中获取相应的数据记录。
在MylSAM里面,其他的索引也在这个.MYI文件里面。
非主键索引跟主键索引存储和检索数据的方式是没有任何区别的,没有主次之分,二者都是在索引文件里面找到磁盘地址,然后到数据文件里面获取数据。
这个就是MylSAM里面的索引落地的形式。但是在的InnoDB里面是不一样的。
InnoDB
在InnoDB中,除了.frm文件,就只有一个.ibd文件,也就是说它的索引和数据都存放在这个文件里。也就是说在索引的叶子节点上,它是直接存储了我们的数据,不再是存储地址。 这也就是为什么说在InnoDB中索引即数据,数据即索引
,就是这个原因。
InnoDB中多个索引,每个索引都会把完整记录在叶子节点放一份吗?
并不会,因为这会带来额外的存储空间浪费和计算消耗。一张InnoDB的表可能有很多个多索引,总不可能每个索引的叶子节点上都存一份数据,因为这样每增加一个索引会导致磁盘的空间占用成倍增加;而且在新增数据的时候,还需要在多颗B+Tree上面操作,既浪费空间,又浪费时间。
完整记录肯定是只有—份的。
InnoDB中完整记录放哪个索引的叶子节点?
其中有一个特殊的索引,这个索引就叫'聚集索引(聚簇索引)'
,所谓聚集索引就是索引键值的逻辑顺序跟表数据行的物理存储顺序是一致的,它的叶子节点上存放完整的记录行。
聚集索引/聚簇索引
'聚集索引(聚簇索引)'
,就是索引键值的逻辑顺序跟表数据行的物理存储顺序是一致的,它的叶子节点上存放完整的记录行。比如字典的目录是按拼音排序的,内容也是按拼音排序的,按拼音排序的这种目录就叫聚集索引。
InnoDB组织数据的方式就是(聚集)索引组织表(clustered index organize table)。 如果说一张表创建了主键索引,那么这个主键索引就是聚集索引,决定数据行的物理存储顺序。
InnoDB中其它索引(二级索引),叶子节点上没有数据怎么检索完整数据?
InnoDB中,主键索引和辅助索引是有一个主次之分的。如果有主键索引,那么主键索引就是聚集索引,其他的索引统一叫做'二级索引(secondary index)'
。
二级索引的叶子节点不存放完整的数据,那检索数据必然要到主键索引的叶子节点上拿到它的所有记录,也就是说,他需要存一个东西,能够完成它到达主键索引的叶子节点取数据的东西。
二级索引存储的是二级索引的键值,例如在name上建立索引,节点上存的是name的值,'Susan'
等等(很明显,它的键值逻辑顺序跟物理行的顺序不一致)。二级索引的叶子节点存的是这条记录对应的主键的值。比如Susan id = 3
。
二级索引需要先扫描自己的B+Tree,然后再根据二级索引的叶子节点找到主键索引的叶子节点拿到数据。从这个角度来说,因为主键索引比二级索引少扫描了一棵B+Tree(避免了回表),它的速度相对会快一些。
回表
回表:非主键索引,我们先通过索引找到主键索引的键值,再通过主键值查出索引里面没有的数据,它比基于主键索引的查询多扫描了一棵索引树,这个过程就叫回表。
二级索引检索数据的流程是这样的:
当我们用name索引查询一条记录,它会在二级索引的叶子节点找到name=Susan
,拿到主键值,也就是id = 3
,然后再到主键索引的叶子节点拿到数据。
InnoDB中二级索引为什么不存地址而是存键值?
因为地址会变化。当你的数据不断地新增和修改的时候,B+Tree也在不断地分裂和合并,那么数据的地址也会对应的会发生变化,那如果其他索引记录的是地址,其它索引的B+Tree都要改一遍,太麻烦了,所以其它索引存了一个不变的值,就是聚集索引的值。
InnoDB中如果一张表没有主键怎么办?那完整的记录放在哪个索引的叶子节点?或者, 这张表根本没有索引呢?数据放在哪里?
MySQL官网介绍:https://dev.mysql.com/doc/refman/5.7/en/innodb-index-types.html
- 如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引
- 如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引
- 如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的row ID作为隐藏的聚集索引,它会随着行记录的写入而主键递增
row ID如何理解?
- 当表中存在一个数字类型的单列的主键时,row ID就是指这个主键列。
- 当表中不存在主键,但存在一个数字类型的非空唯一列时,row ID其实就是指的是对应非空唯一列。
可以这样理解:
row ID并不是真实存在的列,row ID本质是一个非空、唯一的列的别名。
以下三种情况不能使用row ID查询:
- 主键列或者非空唯一列的类型不是数字类型——主键是聚集索引
- 主键是联合主键——主键是聚集索引
- 唯一列不是非空的,row ID没有指向任何一列,而是创建了一个6字节的隐藏列,作为聚集索引(不能显式查到,不代表不存在)
可以下面语句查询一张表的row ID的信息
select _rowid from stu_innodb;
如果这张表什么索引都没,查询_rowid会查不到,虽然不能显式查到,不代表不存在
这个时候在id上加一个唯一索引,并且不允许为null
再次查询
这里可以看到row ID的查询结果就是刚加的唯一索引id的结果集,所以row ID本质是一个非空、唯一的列的别名。
MySQL合集
MySQL1:MySQL发展史,MySQL流行分支及其对应存储引擎
MySQL2:MySQL中一条查询SQL是如何执行的?
MySQL3:MySQL中一条更新SQL是如何执行的?
MySQL4:索引是什么;索引类型;索引存储模型发展:1.二分查找,2.二叉查找树,3.平衡二叉树,4.多路平衡查找树,5. B+树,6.索引为什么不用红黑树?7.InnoDB的hash索引指什么?
MySQL5:MySQL数据存储文件;MylSAM中索引和数据是两个独立的文件,它是如何通过索引找到数据呢?聚集索引/聚簇索引,InnoDB中二级索引为什么不存地址而是存键值?row ID如何理解?
MySQL6:索引使用原则,联合索引,联合主键/复合主键,覆盖索引、什么是回表?索引条件下推,索引的创建与使用,索引的创建与使用,索引失效