## 16.3 MEMORY 存储引擎

[](<>)[](<>)[](<>)[](<>)

这`记忆`存储引擎（以前称为`堆`) 创建具有存储在内存中的内容的专用表。由于数据容易受到崩溃、硬件问题或断电的影响，因此只能将这些表用作临时工作区或只读缓存，用于从其他表中提取的数据。

[](<>)

**表 16.4 内存存储引擎特性**

| 特征 | 支持 |
| --- | --- |
| **B树索引** | 是的 |
| **备份/时间点恢复**（在服务器中实现，而不是在存储引擎中。） | 是的 |
| **集群数据库支持** | 不 |
| **聚集索引** | 不 |
| **压缩数据** | 不 |
| **数据缓存** | 不适用 |
| **加密数据** | 是（通过加密功能在服务器中实现。） |
| **外键支持** | 不 |
| **全文检索索引** | 不 |
| **地理空间数据类型支持** | 不 |
| **地理空间索引支持** | 不 |
| **哈希索引** | 是的 |
| **索引缓存** | 不适用 |
| **锁定粒度** | 桌子 |
| **MVCC** | 不 |
| **复制支持**（在服务器中实现，而不是在存储引擎中。） | 有限（参见本节后面的讨论。） |
| **存储限制** | 内存 |
| **T-树索引** | 不 |
| **交易** | 不 |
| **更新数据字典的统计信息** | 是的 |

-   [何时使用 MEMORY 或 NDB Cluster](memory-storage-engine.html#memory-storage-engine-compared-cluster)

-   [分区](memory-storage-engine.html#memory-storage-engine-partitioning)

-   [性能特点](memory-storage-engine.html#memory-storage-engine-performance-characteristics)

-   [MEMORY 表的特征](memory-storage-engine.html#memory-storage-engine-characteristics-of-memory-tables)

-   [MEMORY 表的 DDL 操作](memory-storage-engine.html#memory-storage-engine-ddl-operations-for-memory-tables)

-   [索引](memory-storage-engine.html#memory-storage-engine-indexes)

-   [用户创建的临时表](memory-storage-engine.html#memory-storage-engine-user-created-and-temporary-tables)

-   [加载数据中](memory-storage-engine.html#memory-storage-engine-loading-data)

-   [内存表和复制](memory-storage-engine.html#memory-tables-replication)

-   [管理内存使用](memory-storage-engine.html#memory-storage-engine-managing-memory-use)

-   [其他资源](memory-storage-engine.html#memory-storage-engine-additional-resources)

### 何时使用 MEMORY 或 NDB Cluster

希望部署使用`记忆`重要、高可用或经常更新数据的存储引擎应考虑 NDB Cluster 是否是更好的选择。一个典型的用例`记忆`引擎涉及以下特性：

-   涉及瞬态、非关键数据的操作，例如会话管理或缓存。当 MySQL 服务器停止或重新启动时，`记忆`表丢失。

-   内存存储，可实现快速访问和低延迟。数据量可以完全适合内存，而不会导致操作系统换出虚拟内存页面。

-   只读或以读取为主的数据访问模式（有限更新）。

    NDB Cluster 提供与`记忆`引擎具有更高的性能水平，并提供其他功能不可用`记忆`：

-   用于客户端之间低争用的行级锁定和多线程操作。

-   即使是包含写入的语句混合也具有可伸缩性。

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

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

-   跨节点的自动数据分发；应用程序开发人员不需要制作自定义分片或分区解决方案。

-   支持可变长度数据类型（包括[`BLOB`](blob.html)and[`TEXT`](blob.html)) not supported by`MEMORY`.

### Partitioning

`MEMORY`tables cannot be partitioned.

### Performance Characteristics

`MEMORY`performance is constrained by contention resulting from single-thread execution and table lock overhead when processing updates. This limits scalability when load increases, particularly for statement mixes that include writes.

Despite the in-memory processing for`MEMORY`tables, they are not necessarily faster than[`InnoDB`](innodb-storage-engine.html)tables on a busy server, for general-purpose queries, or under a read/write workload. In particular, the table locking involved with performing updates can slow down concurrent usage of`MEMORY`tables from multiple sessions.

Depending on the kinds of queries performed on a`MEMORY`table, you might create indexes as either the default hash data structure (for looking up single values based on a unique key), or a general-purpose B-tree data structure (for all kinds of queries involving equality, inequality, or range operators such as less than or greater than). The following sections illustrate the syntax for creating both kinds of indexes. A common performance issue is using the default hash indexes in workloads where B-tree indexes are more efficient.

### Characteristics of MEMORY Tables

The`MEMORY`storage engine does not create any files on disk. The table definition is stored in the MySQL data dictionary.

`MEMORY`tables have the following characteristics:

-   空间`记忆`表被分配在小块中。表对插入使用 100% 动态散列。不需要溢出区域或额外的键空间。空闲列表不需要额外的空间。删除的行被放在一个链表中，并在您向表中插入新数据时重复使用。`记忆`表也​​没有通常与哈希表中的删除和插入相关的问题。

-   `记忆`表使用固定长度的行存储格式。可变长度类型，例如[`VARCHAR`](char.html)使用固定长度存储。

-   `记忆`表不能包含[`斑点`](blob.html)要么[`文本`](blob.html)列。

-   `记忆`包括支持`自动递增`列。

-   非-`暂时的` `记忆`表在所有客户端之间共享，就像任何其他非`暂时的`桌子。

### MEMORY 表的 DDL 操作

创建一个`记忆`表，指定子句`引擎=内存`在[`创建表`](create-table.html)陈述。

```
CREATE TABLE t (i INT) ENGINE = MEMORY;
```

如引擎名称所示，`记忆`表存储在内存中。它们默认使用哈希索引，这使得它们对于单值查找非常快，并且对于创建临时表非常有用。但是，当服务器关闭时，所有存储在`记忆`表丢失。表本身继续存在，因为它们的定义存储在 MySQL 数据字典中，但在服务器重新启动时它们是空的。

此示例展示了如何创建、使用和删除`记忆`桌子：

```
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;
```

最大尺寸`记忆`表是由[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)系统变量，默认值为 16MB。强制执行不同的大小限制`记忆`表，更改此变量的值。有效值[`创建表`](create-table.html)，或随后的[`更改表`](alter-table.html)要么[`截断表`](truncate-table.html), 是用于表生命周期的值。服务器重新启动还会设置现有的最大大小`记忆`表到全球[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)价值。您可以设置单个表格的大小，如本节后面所述。

### 索引

这`记忆`存储引擎同时支持`哈希`和`BTREE`索引。您可以通过添加一个给定索引指定一个或另一个`使用`子句如下所示：

```
CREATE TABLE lookup
    (id INT, INDEX USING HASH (id))
    ENGINE = MEMORY;
CREATE TABLE lookup
    (id INT, INDEX USING BTREE (id))
    ENGINE = MEMORY;
```

有关 B 树和哈希索引的一般特征，请参阅[第 8.3.1 节，“MySQL 如何使用索引”](mysql-indexes.html).

`记忆`每个表最多可以有 64 个索引，每个索引 16 列，最大键长度为 3072 字节。

如果一个`记忆`表哈希索引具有高度的键重复（许多索引条目包含相同的值），对影响键值的表的更新和所有删除都明显变慢。这种放缓的程度与重复程度成正比（或与索引基数成反比）。你可以使用一个`BTREE`索引来避免这个问题。

`记忆`表可以有非唯一键。（对于哈希索引的实现来说，这是一个不常见的特性。）

被索引的列可以包含`空值`价值观。

### 用户创建的临时表

`记忆`表内容存储在内存中，这是一个属性`记忆`表与服务器在处理查询时动态创建的内部临时表共享。但是，这两种类型的表的不同之处在于`记忆`表不受存储转换的影响，而内部临时表是：

-   如果内部临时表变得太大，服务器会自动将其转换为磁盘存储，如中所述[第 8.4.4 节，“MySQL 中的内部临时表使用”](internal-temporary-tables.html).

-   用户创建`记忆`表永远不会转换为磁盘表。

### 加载数据中

填充一个`记忆`MySQL 服务器启动时的表，您可以使用[`初始化文件`](server-system-variables.html#sysvar_init_file)系统变量。例如，您可以将语句如[`插入...选择`](insert-select.html)要么[`加载数据`](load-data.html)到文件中以从持久数据源加载表，并使用[`初始化文件`](server-system-variables.html#sysvar_init_file)命名文件。看[第 5.1.8 节，“服务器系统变量”](server-system-variables.html)， 和[第 13.2.7 节，“加载数据语句”](load-data.html).

### 内存表和复制

当复制源服务器关闭并重新启动时，其[`记忆`](memory-storage-engine.html)表变空。要将这种效果复制到副本，源第一次使用给定的[`记忆`](memory-storage-engine.html)表启动后，它会记录一个事件，通知副本必须通过写入一个表来清空表[`删除`](delete.html)或（来自 MySQL 8.0.22）[`截断表`](truncate-table.html)将该表的语句写入二进制日志。当副本服务器关闭并重新启动时，它的[`记忆`](memory-storage-engine.html)表也​​变空了，它写了一个[`删除`](delete.html)或（来自 MySQL 8.0.22）[`截断表`](truncate-table.html)声明到它自己的二进制日志，它被传递到任何下游副本。

当你使用[`记忆`](memory-storage-engine.html)复制拓扑中的表，在某些情况下，源上的表和副本上的表可能不同。有关处理每种情况以防止过时读取或错误的信息，请参阅[第 17.5.1.21 节，“复制和内存表”](replication-features-memory.html).

### 管理内存使用

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

如果您从`记忆`桌子。只有当整个表被删除时才会回收内存。以前用于删除行的内存将重新用于同一表中的新行。释放所有使用的内存`记忆`当您不再需要表的内容时，执行[`删除`](delete.html)要么[`截断表`](truncate-table.html)删除所有行，或使用完全删除表[`删除表`](drop-table.html).要释放已删除行使用的内存，请使用`更改表引擎=内存`强制重建表。

一行中需要的内存`记忆`使用以下表达式计算表：

```
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*))
```

`对齐（）`表示一个舍入因子，以使行长度成为行长度的精确倍数`字符`指针大小。`大小（字符*）`在 32 位机器上为 4，在 64 位机器上为 8。

如前所述，[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)系统变量设置最大大小的限制`记忆`表。要控制单个表的最大大小，请在创建每个表之前设置此变量的会话值。（不要改变全局[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)值，除非您打算将该值用于`记忆`所有客户端创建的表。）以下示例创建两个`记忆`表，最大大小分别为 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`](server-system-variables.html#sysvar_max_heap_table_size)服务器重新启动时的值。

您还可以指定一个`MAX_ROWS`表选项在[`创建表`](create-table.html)声明为`记忆`表以提供有关您计划在其中存储的行数的提示。这不会使表超出[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)值，它仍然作为最大表大小的约束。为了能够使用的最大灵活性`MAX_ROWS`， 放[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)至少与您希望每个的值一样高`记忆`表能够增长。

### 其他资源

一个专门的论坛`记忆`存储引擎可在<https://forums.mysql.com/list.php?92>.
