MEMORY
存储引擎(以前称为 HEAP
)创建特殊用途的表,其内容存储在内存中。由于数据容易受到崩溃、硬件问题或电源故障的影响,因此仅将这些表用作临时工作区或从其他表提取数据的只读缓存。
表 18.4 MEMORY 存储引擎功能
功能 | 支持 |
---|---|
B 树索引 | 是 |
备份/时间点恢复(在服务器中实现,而不是在存储引擎中实现。) | 是 |
集群数据库支持 | 否 |
聚簇索引 | 否 |
压缩数据 | 否 |
数据缓存 | N/A |
加密数据 | 是(通过加密函数在服务器中实现。) |
外键支持 | 否 |
全文搜索索引 | 否 |
地理空间数据类型支持 | 否 |
地理空间索引支持 | 否 |
哈希索引 | 是 |
索引缓存 | N/A |
锁定粒度 | 表 |
MVCC | 否 |
复制支持(在服务器中实现,而不是在存储引擎中实现。) | 有限(请参阅本节后面的讨论。) |
存储限制 | RAM |
T 树索引 | 否 |
事务 | 否 |
更新数据字典的统计信息 | 是 |
希望部署使用 MEMORY
存储引擎来处理重要、高可用或频繁更新数据的应用程序的开发人员应考虑 NDB 集群是否更好的选择。 MEMORY
引擎的典型用例涉及以下特征
涉及瞬态、非关键数据的操作,例如会话管理或缓存。当 MySQL 服务器停止或重新启动时,
MEMORY
表中的数据将丢失。用于快速访问和低延迟的内存中存储。数据量可以完全适合内存,而不会导致操作系统交换出虚拟内存页。
只读或以读为主的数据访问模式(有限更新)。
NDB 集群提供与 MEMORY
引擎相同的功能,但性能水平更高,并提供 MEMORY
不具备的其他功能
MEMORY
的性能受处理更新时单线程执行和表锁定开销导致的争用限制。当负载增加时,这会限制可扩展性,尤其是在包含写入的语句混合中。
尽管 MEMORY
表进行内存中处理,但在繁忙的服务器上,它们在处理通用查询或在读写工作负载下并不一定比 InnoDB
表快。特别是,执行更新所涉及的表锁定会减慢来自多个会话的对 MEMORY
表的并发使用。
根据对 MEMORY
表执行的查询类型,可以创建索引作为默认的哈希数据结构(用于根据唯一键查找单个值)或通用 B 树数据结构(用于涉及等式、不等式或范围运算符(例如小于或大于)的所有类型的查询)。以下各节说明了创建两种索引的语法。常见的性能问题是在 B 树索引效率更高的工作负载中使用默认的哈希索引。
MEMORY
存储引擎不会在磁盘上创建任何文件。表定义存储在 MySQL 数据字典中。
MEMORY
表具有以下特征
要创建 MEMORY
表,请在 CREATE TABLE
语句上指定子句 ENGINE=MEMORY
。
CREATE TABLE t (i INT) ENGINE = MEMORY;
正如引擎名称所暗示的,MEMORY
表存储在内存中。它们默认使用哈希索引,这使得它们对于单值查找非常快,对于创建临时表也非常有用。但是,当服务器关闭时,存储在 MEMORY
表中的所有行都会丢失。表本身继续存在,因为它们的定义存储在 MySQL 数据字典中,但在服务器重新启动时它们为空。
此示例演示了如何创建、使用和删除 MEMORY
表
mysql> CREATE TABLE test ENGINE=MEMORY
SELECT ip,SUM(downloads) AS down
FROM log_table GROUP BY ip;
mysql> SELECT COUNT(ip),AVG(down) FROM test;
mysql> DROP TABLE test;
MEMORY
表的最大大小受 max_heap_table_size
系统变量限制,该变量的默认值为 16MB。要为 MEMORY
表强制执行不同的大小限制,请更改此变量的值。对 CREATE TABLE
、后续 ALTER TABLE
或 TRUNCATE TABLE
生效的值将用作该表生命周期的值。服务器重启也将现有 MEMORY
表的最大大小设置为全局 max_heap_table_size
值。您可以为各个表设置大小,如本节后面所述。
MEMORY
存储引擎支持 HASH
和 BTREE
索引。您可以通过添加 USING
子句为给定索引指定其中一个,如下所示
CREATE TABLE lookup
(id INT, INDEX USING HASH (id))
ENGINE = MEMORY;
CREATE TABLE lookup
(id INT, INDEX USING BTREE (id))
ENGINE = MEMORY;
有关 B 树索引和哈希索引的一般特征,请参阅 第 10.3.1 节,“MySQL 如何使用索引”.
MEMORY
表每个表最多可以有 64 个索引,每个索引最多有 16 列,最大键长度为 3072 字节。
如果一个MEMORY
表的哈希索引具有高度的键重复(许多索引条目包含相同的值),则影响键值的表更新和所有删除操作的速度会明显下降。这种减速的程度与重复程度成正比(或与索引基数成反比)。您可以使用BTREE
索引来避免此问题。
MEMORY
表可以具有非唯一键。(对于哈希索引的实现,这是一个不常见的特性。)
被索引的列可以包含NULL
值。
MEMORY
表的内容存储在内存中,这是一个MEMORY
表与服务器在处理查询时动态创建的内部临时表共有的属性。但是,这两种类型的表有所不同,因为MEMORY
表不受存储转换的影响,而内部临时表则会受到影响。
如果内部临时表变得太大,服务器会自动将其转换为磁盘存储,如第 10.4.4 节,“MySQL 中内部临时表的用法”中所述。
用户创建的
MEMORY
表永远不会转换为磁盘表。
要在 MySQL 服务器启动时填充MEMORY
表,您可以使用init_file
系统变量。例如,您可以将类似INSERT INTO ... SELECT
或LOAD DATA
的语句放到一个文件中,以从持久数据源加载表,并使用init_file
来命名该文件。请参阅第 7.1.8 节,“服务器系统变量”和第 15.2.9 节,“LOAD DATA 语句”。
当复制源服务器关闭并重新启动时,其MEMORY
表将变为空。为了将这种影响复制到副本,源服务器在启动后第一次使用给定的MEMORY
表时,会记录一个事件,该事件通知副本必须通过将该表的TRUNCATE TABLE
语句写入二进制日志来清空该表。当副本服务器关闭并重新启动时,其MEMORY
表也将变为空,它会将一个TRUNCATE TABLE
语句写入自己的二进制日志,该日志将传递给任何下游副本。
当您在复制拓扑中使用MEMORY
表时,在某些情况下,源服务器上的表和副本上的表可能有所不同。有关处理每种情况以防止陈旧读取或错误的信息,请参阅第 19.5.1.21 节,“复制和 MEMORY 表”。
服务器需要足够的内存来维护所有同时使用的MEMORY
表。
如果您从MEMORY
表中删除单个行,则不会回收内存。只有在删除整个表时才会回收内存。以前用于已删除行的内存将被重复用于同一表中的新行。要释放MEMORY
表不再需要其内容时使用的所有内存,请执行DELETE
或TRUNCATE TABLE
删除所有行,或者使用DROP TABLE
完全删除该表。要释放已删除行使用的内存,请使用ALTER TABLE ENGINE=MEMORY
强制重建表。
使用以下表达式计算MEMORY
表中一行所需的内存
SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) * 4)
+ SUM_OVER_ALL_HASH_KEYS(sizeof(char*) * 2)
+ ALIGN(length_of_row+1, sizeof(char*))
ALIGN()
代表一个舍入因子,它会导致行长度成为char
指针大小的精确倍数。sizeof(char*)
在 32 位机器上为 4,在 64 位机器上为 8。
如前所述,max_heap_table_size
系统变量设置了MEMORY
表的最大大小限制。要控制各个表的最大大小,请在创建每个表之前设置该变量的会话值。(除非您打算将该值用于所有客户端创建的MEMORY
表,否则不要更改全局max_heap_table_size
值。)以下示例创建了两个MEMORY
表,它们的最大大小分别为 1MB 和 2MB
mysql> SET max_heap_table_size = 1024*1024;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE t1 (id INT, UNIQUE(id)) ENGINE = MEMORY;
Query OK, 0 rows affected (0.01 sec)
mysql> SET max_heap_table_size = 1024*1024*2;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE t2 (id INT, UNIQUE(id)) ENGINE = MEMORY;
Query OK, 0 rows affected (0.00 sec)
如果服务器重新启动,这两个表将恢复到服务器的全局max_heap_table_size
值。
您还可以在MEMORY
表的CREATE TABLE
语句中指定MAX_ROWS
表选项,以提供有关您计划存储在其中的行数的提示。这不会使表能够超过max_heap_table_size
值,该值仍然作为最大表大小的限制。为了在使用MAX_ROWS
方面获得最大的灵活性,请将max_heap_table_size
设置为至少与您希望每个MEMORY
表能够增长的值一样高。
一个专门针对MEMORY
存储引擎的论坛位于https://forums.mysql.com/list.php?92。