相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  替代存储引擎  /  MEMORY 存储引擎

18.3 MEMORY 存储引擎

MEMORY 存储引擎(以前称为 HEAP)创建特殊用途的表,其内容存储在内存中。由于数据容易受到崩溃、硬件问题或电源故障的影响,因此仅将这些表用作临时工作区或从其他表中提取数据的只读缓存。

表 18.4 MEMORY 存储引擎特性

特性 支持
B 树索引
备份/时间点恢复 (在服务器中实现,而不是在存储引擎中。)
集群数据库支持
聚集索引
压缩数据
数据缓存 N/A
加密数据 是(在服务器中通过加密函数实现。)
外键支持
全文搜索索引
地理空间数据类型支持
地理空间索引支持
哈希索引
索引缓存 N/A
锁定粒度
MVCC
复制支持 (在服务器中实现,而不是在存储引擎中。) 有限(请参阅本节后面的讨论。)
存储限制 RAM
T 树索引
事务
更新数据字典的统计信息

何时使用 MEMORY 或 NDB Cluster

希望部署使用 MEMORY 存储引擎来存储重要、高可用或频繁更新数据的应用程序的开发人员应考虑 NDB Cluster 是否是更好的选择。MEMORY 引擎的典型用例涉及以下特征

  • 涉及瞬态、非关键数据的操作,例如会话管理或缓存。当 MySQL 服务器停止或重启时,MEMORY 表中的数据会丢失。

  • 用于快速访问和低延迟的内存内存储。数据量可以完全放在内存中,而不会导致操作系统交换虚拟内存页。

  • 只读或主要读取的数据访问模式(有限更新)。

NDB Cluster 提供与 MEMORY 引擎相同的特性,但性能水平更高,并提供 MEMORY 不具备的其他特性

  • 行级锁定和多线程操作,可减少客户端之间的争用。

  • 即使在包含写入的语句混合中也能实现可扩展性。

  • 可选的磁盘支持操作,用于数据持久性。

  • 无共享架构和多主机操作,没有单点故障,可实现 99.999% 的可用性。

  • 跨节点自动数据分布;应用程序开发人员无需设计自定义分片或分区解决方案。

  • 支持可变长度数据类型(包括 BLOBTEXT),MEMORY 不支持。

分区

MEMORY 表不能分区。

性能特征

MEMORY 的性能受单线程执行和处理更新时的表锁定开销造成的争用限制。这限制了负载增加时的可扩展性,特别是对于包含写入的语句混合。

尽管 MEMORY 表进行的是内存内处理,但对于繁忙的服务器上的通用查询或读/写工作负载来说,它们不一定比 InnoDB 表更快。特别是,执行更新所涉及的表锁定会减慢多个会话对 MEMORY 表的并发使用。

根据对 MEMORY 表执行的查询类型,您可以创建索引作为默认的哈希数据结构(用于根据唯一键查找单个值),或通用 B 树数据结构(用于所有涉及相等、不相等或范围运算符(例如小于或大于)的查询)。以下部分说明了创建这两种索引的语法。一个常见的性能问题是在 B 树索引更有效的工作负载中使用默认的哈希索引。

MEMORY 表的特征

MEMORY 存储引擎不会在磁盘上创建任何文件。表定义存储在 MySQL 数据字典中。

MEMORY 表具有以下特征

  • MEMORY 表的空间以小块分配。表使用 100% 的动态哈希进行插入。不需要溢出区域或额外的键空间。不需要额外的空间用于空闲列表。已删除的行放在一个链表中,并在您将新数据插入表中时被重用。MEMORY 表也不存在与哈希表中删除加插入相关的常见问题。

  • MEMORY 表使用固定长度的行存储格式。可变长度类型(例如 VARCHAR)使用固定长度存储。

  • MEMORY 表不能包含 BLOBTEXT 列。

  • MEMORY 包含对 AUTO_INCREMENT 列的支持。

  • 非 TEMPORARY 的 MEMORY 表在所有客户端之间共享,就像任何其他非 TEMPORARY 表一样。

MEMORY 表的 DDL 操作

要创建 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 表不受存储转换的影响,而内部临时表则会受到影响。

加载数据

要在 MySQL 服务器启动时填充 MEMORY 表,可以使用 init_file 系统变量。例如,您可以将类似于 INSERT INTO ... SELECTLOAD DATA 的语句放入一个文件中,以从持久数据源加载表,并使用 init_file 来命名该文件。请参阅 Section 7.1.8, “Server System Variables”Section 15.2.9, “LOAD DATA Statement”

MEMORY 表和复制

当复制源服务器关闭并重新启动时,其 MEMORY 表将变为空。为了将这种效果复制到副本,源服务器在启动后第一次使用给定的 MEMORY 表时,它会记录一个事件,通知副本必须通过对该表写入 TRUNCATE TABLE 语句来清空表,并将该语句写入二进制日志。当副本服务器关闭并重新启动时,其 MEMORY 表也会变为空,并且它会将其自己的二进制日志写入 TRUNCATE TABLE 语句,该语句将传递给任何下游副本。

当您在复制拓扑中使用 MEMORY 表时,在某些情况下,源服务器上的表和副本上的表可能有所不同。有关处理这些情况的每种情况以防止陈旧读取或错误的信息,请参阅 Section 19.5.1.22, “Replication and MEMORY Tables”

管理内存使用

服务器需要足够的内存来维护所有同时使用的 MEMORY 表。

如果您从 MEMORY 表中删除单个行,内存不会被回收。只有当整个表被删除时,才会回收内存。以前用于已删除行的内存将被重新用于同一表中的新行。要释放 MEMORY 表不再需要其内容时使用的所有内存,请执行 DELETETRUNCATE 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 指针大小的精确倍数。在 32 位机器上 sizeof(char*) 为 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 值。

您还可以在 CREATE TABLE 语句中为 MEMORY 表指定 MAX_ROWS 表选项,以提供有关您计划在其中存储的行数的提示。这不会使表能够超过 max_heap_table_size 值,该值仍然是最大表大小的约束。为了最大限度地利用 MAX_ROWS 的灵活性,请将 max_heap_table_size 设置为至少与您希望每个 MEMORY 表能够增长到的值一样高。

其他资源

一个专门讨论 MEMORY 存储引擎的论坛可在 https://forums.mysql.com/list.php?92 获取。