Skip to content

38 | 都说InnoDB好,那还要不要使用Memory引擎? #51

@git-zjx

Description

@git-zjx

示例表

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

Memory 引擎的数据组织结构

Memory 引擎的数据和索引是分开的,数据部分以数组的方式单独存放,而主键 id 索引存放的是每个数据的位置,而且主键 id 是 hash 索引,索引上的 key 并不是有序的,这种数据组织形式称为堆组织表

image

Memory 引擎的一些特性:

  1. 数据安装写入顺序存放
  2. 当数据文件有空洞的时候,找到空位就可以插入新值
  3. 数据位置发生变化是,需要修改所有索引
  4. 使用普通索引查询时,不用走两遍索引
  5. 不支持 Blob 和 Text,并且即使定义了 varchar(N),也会当作 char(N) 来处理
  6. 因为主键索引是哈希索引,执行范围查询是需要走全表扫描

hash 索引和 B-Tree 索引

Memory 引擎是支持 B-Tree 索引的,和 InnoDB 的 B+ 树索引组织形式类似

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

这时,表 t1 的数据组织形式如下:

image

两种索引的查询结果的区别:

image

Memory 引擎的锁

Memory 引擎不支持行锁,只支持表锁,一张表只要有更新,就会堵住其他所有在这个表上的读写操作,在并发访问和处理并发事务的时候 ,性能不会太好

数据持久性问题

image

M-S 结构下,下面这个时序就会出现问题:

  1. 业务正常访问主库
  2. 备库硬件升级,备库重启,内存表 t1 内容被清空
  3. 备库重启后,客户端发送一条 update 语句,修改表 t1 的数据行,这时备库应用线程就会报错 “找不到要更新的行”

这种情况下,业务端能够感知到异常,可能还好处理。

但还有一种情况是在双 M 结构下,由于 MySQL 知道重启之后,内存表的数据会丢失,所以,担心主库重启后,出现主备不一致,会往 binlog 里面写入 DELETE FROM t1 ,造成主库的内存表突然被清空

image

使用场景

理论上建议把普通内存表都使用 InnoDB 表代替,但在使用用户临时表时,如果数据量可控,可以考虑使用内存表,主要基于以下考虑:

  1. 临时表不会被其他线程访问,没有并发性问题
  2. 临时表重启后也是需要删除的,清空数据这个问题不存在
  3. 备库的临时表也不会影响主库的用户线程
  4. 内存表不需要写磁盘,写速度更快
  5. 内存表使用 hash 索引,查询速度更快

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions