内存表的数据组织结构

创建两个结构一样的表,但是使用不同的引擎

create table t1(id int primary key, c int) engine=Memory;
create table t2(id int primary key, c int) engine=innodb;
insert into t1 values(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
insert into t2 values(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);

查看两个表的数据,可以看到内存表t1里0在最后一行,而innodb表t2中0在第一行。

这就与两个引擎的主键索引的组织方式有关了。 innodb引擎的主键是B+树的方式组织的,主键索引上的值是有序存储的。所以0会出现在第一行。

Memory引擎的数据和索引是分开的,内存表的数据部分以数组的方式单独存放,而在主键id索引里,存的是每个数据的位置。主键id是hash索引,可以看到索引上的key并不是有序的。

所以:

  • InnoDB引擎把数据放在主键索引上,其它索引上保存的是主键id,这种方式,我们称之为索引组织表
  • Memory引擎把数据单独存放,索引上保存数据位置的数据组织形式,称之为堆组织表

InnoDB与Memory引擎的不同:

  1. InnoDB表的数据总是有序存放的,而内存表的数据就是按照写入顺序存放的。
  2. 当数据文件有空洞的时候,InnoDB表在插入新数据的时候,为了保证数据的有序性,只能在固定的位置写入新值,而内存表找到空位就可以插入。
  3. 数据位置变化的时候,InnoDB只需要改变主键索引,而内存表需要修改所有索引
  4. InnoDB表用主键索引查询时只需要走一次索引查找,用普通索引查询的时候,需要走两次索引查找。而内存表没有这个区别,所有索引的地位相同。
  5. InnoDB支持变长数据类型,不同记录的长度可能不同;内存表不支持Blob和Text字段,并且即使定义了varchar(N),实际也当作char(N),也就是固定长度字符串来存储,因此内存表的每行数据长度相同。

内存表每个数据行被删除之后,空出的这个位置都可以被接下来要插入的数据复用

因为内存表的主键是hash索引,所以范围查询需要走全局扫描。

hash索引和B-Tree索引

内存表也可以支持B-Tree索引。在id列上创建一个B-Tree索引,SQL语句可以这样写

alter table t1 add index a_btree_index using btree (id);

这样数据的组织形式就变成了这样:

不建议使用内存表的原因

锁粒度问题

内存表只支持表锁。

数据持久化问题

数据库重启的时候,所有的内存表都会被清空