Author: mateng
内存表,就是放在内存中的表,所使用内存的大小可通过My.cnf中的max_heap_table_size指定,如max_heap_table_size=1024M 内存表满后,会提示数据满错误。 ERROR 1114 (HY000): The table ‘abc’ is full
mysql> show create table heap_test;
| heap_test | CREATE TABLE `heap_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`a1` char(8) DEFAULT NULL,
`a2` char(8) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `a1` (`a1`(2))
) ENGINE=MEMORY AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
因为内存表有两个主要的特性
所以内存表很适合作为缓存,存储中间结果,和需要频繁访问的数据。
缺点也很明显,数据存在内存中, 服务器重启后数据会丢失。
创建内存表的相关参数 internal_tmp_mem_storage_engine
以下代码调研 临时表引擎为 memory
代码调用栈
Sql_cmd_create_table::execute -> mysql_create_table -> mysql_create_table_no_lock -> create_table_impl -> rea_create_base_table -> ha_create_table -> handler::ha_create -> ha_heap::create
代码接口:ha_heap::create 这个接口做的事情主要是
PS: MEMORY 引擎会将数据记录在一些定长的内存块中,每个内存块中记录数目存储在 HP_BLOCK 类中的
uint records_in_block{0}; /* Records in one heap-block */
每条记录的长度存储在 HP_BLOCK 中的 uint recbuffer{0}; / * Length of one saved record * / 给每条记录分配空间的内存长度为 recbuffer + 1, 最后一位是标记位,value = 1 为未删除,value = 0 为删除。
Memory 有两个全局变量,heap_open_list and heap_share_list.
查询时内存表主要会做三个步骤 开表 -> 预算有多少记录->读记录 代码接口: ha_heap::open -> ha_heap::info ->ha_heap::rnd_init
开表代码调用栈
open_tables_for_query -> open_tables -> open_and_process_table -> open_table -> open_table_from_share -> handler::ha_open -> ha_heap::open
在 ha_heap::open 这个接口里主要做的事情是
代码接口: ha_heap::close
这是一个释放临时表的接口,主要做的事情是从hp_open_list 中删除相应的HP_INFO, 然后–info->s->open_count, 将于 hp_info 关联的 hp_share 中的技术变量 open_count 减1 并且调用 my_free 释放 hp_info 当这个值减为0时候并且 hp_share 的 delete_on_close 为 true, 则调用 hp_free 释放 hp_share
我们已知内存表的一个特性就是多实例共享,以下从三个方面描述多实例共享。 1.MySQL 建立连接 connect_a,连接的数据库中有 heap 表, MySQL 建立连接 connect_b, 选择与 connect_a 同一个库
这种场景下,当connect_a 建立时,系统会调用
open_table_from_share -> handler::ha_open -> ha_heap::open
打开内存表,同时给当前的线程创建一个属于自己的表描述类,这个表描述类,对应着一个handler 和 HP_INFO 实例。 当 connect_b 建立时,系统的做法同 connect_a 建立时一样,会为当前的线程创建一个属于自己的表描述类,用于操做内存表
2.MySQL 建立连接 connect_a,连接的数据库中没有heap表, MySQL 建立连接 connect_b,选择与 connect_a 同一个库,创建内存表, connect_a, 查询该内存表
这种场景下,当connect_a 建立,系统调用open_table_from_share, 因为库中没有内存表,所以不会调用开启内存表接口的方法,connect_b 建立,也不会调用开启内存表接口的方法,当 connect_b 创建内存表后,系统会调用 创建内存表的接口 ha_heap::create。 表创建好后,connect_a 查询内存表,这个时候系统会为connect_a 的线程创建一个属于自己的表描述类,代码路径是 open_table_from_share -> handler::ha_open -> ha_heap::open
3.MYSQL 建立连接 connect_a, 连接的数据库中有heap表,MySQL 建立连接 connect_b, 选择与 connect_a 同一个表,connect_b 断开连接,MySQL 建立连接 connect_c, 选择与 connect_a 同一个库,并drop 内存表。connect_a 查询内存表 这种场景下,connect_a 和 connect_b,connect_c 建立后,系统都会为他们创建属于自己线程的表描述类,用于操作内存表。 connect_b 断开连接后,不会对内存表有任何影响。connect_c 调用 drop table 后,系统会调用 ha_heap::close 方法,这个方法具体的描述在上文已经阐述,connect_a 再去查内存表会抛出 ERROR 1146, table doesn’t exist 错误。
MySQL 数据库内部的多线程机制,提高了系统的吞吐量,并且提供的是插件式的存储引擎结构,这样就使得每一个表都可以设置自己的存储引擎。内存表也作为一种存储引擎可以供系统的表做选择,每一个表都有自己的一个表描述类(TABLE),多个线程中每个线程在处理请求的时候都会有自己的表描述类,每个表描述类都会分配一个自己的handler类实例,这不仅仅适用与内存表,也适用了其他的存储引擎。这样设计内存表,就是提供一种快速访问的存储引擎。大大提供数据的访问速率。