Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  Alternative Storage Engines  /  The MEMORY Storage Engine

18.3 MEMORY 存储引擎

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

表 18.4 MEMORY 存储引擎特征

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

何时使用 MEMORY 或 NDB Cluster

开发人员想部署使用 MEMORY 存储引擎的应用程序,用于重要的、高可用性或频繁更新的数据,应该考虑 NDB Cluster 是否是一个更好的选择。MEMORY 引擎的典型用例包括:

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

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

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

NDB 集群提供了与 MEMORY 引擎相同的功能,但具有更高的性能水平,并提供了 MEMORY 不具备的其他功能:

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

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

  • 可选的磁盘支持操作,以确保数据持久性。

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

  • 自动数据分布跨节点;应用程序开发者无需编写自定义的分片或分区解决方案。

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

分区

MEMORY 表不能被分区。

性能特征

MEMORY 性能受到单线程执行和表锁定开销的限制,当处理更新时,限制了可扩展性,特别是在包含写入的语句混合中。

尽管 MEMORY 表在内存中处理,但它们并不一定比 InnoDB 表快,特别是在繁忙的服务器上,对于一般的查询或读写工作负载来说。

根据在 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 TABLETRUNCATE TABLE 中生效的值将用于表的整个生命周期。服务器重新启动也将设置现有 MEMORY 表的最大大小为全局 max_heap_table_size 值。你可以按照本节后面所述的方式设置单个表的大小。

索引

MEMORY 存储引擎支持 HASHBTREE 索引。你可以通过添加 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 指定文件名。请参阅 第 7.1.8 节,“服务器系统变量”第 15.2.9 节,“LOAD DATA 语句”

MEMORY 表和复制

当复制源服务器关闭并重新启动时,其 MEMORY 表将变为空。为了将此效果复制到副本中,源服务器在启动后第一次使用给定的 MEMORY 表时,会记录一个事件,以通知副本清空该表,方法是将 TRUNCATE TABLE 语句写入二进制日志中。当副本服务器关闭并重新启动时,其 MEMORY 表也将变为空,并将 TRUNCATE TABLE 语句写入其自己的二进制日志中,该日志将被传递给下游副本。

当您在复制拓扑结构中使用 MEMORY 表时,在某些情况下,源表和副本表可能不同。有关如何处理这些情况以避免陈旧读取或错误的信息,请参阅 第 19.5.1.21 节,“复制和 MEMORY 表”

管理内存使用

服务器需要足够的内存来维护所有同时使用的 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 指针大小的 exact 倍数。sizeof(char*) 在 32 位机器上为 4,在 64 位机器上为 8。

如前所述,max_heap_table_size 系统变量设置了 MEMORY 表的最大大小。要控制单个表的最大大小,请在创建每个表之前设置会话值的这个变量。(不要更改全局 max_heap_table_size 值,除非您打算让该值用于所有客户端创建的 MEMORY 表。)以下示例创建了两个 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 语句中指定 MAX_ROWS 表选项,以提供关于您计划在表中存储的行数的提示。这不会使表能够增长超过 max_heap_table_size 值,该值仍然是表大小的约束。要使 MAX_ROWS 具有最大灵活性,请将 max_heap_table_size 设置至少与您想要每个 MEMORY 表增长到的值相同。

附加资源

有一个专门的论坛致力于 MEMORY 存储引擎,位于 https://forums.mysql.com/list.php?92