MEMORY 存储引擎(以前称为 HEAP)创建特殊用途的表,其内容存储在内存中。由于数据容易受到崩溃、硬件问题或电源故障的影响,因此仅将这些表用作临时工作区或从其他表中提取数据的只读缓存。
表 18.4 MEMORY 存储引擎特性
特性 | 支持 |
---|---|
B 树索引 | 是 |
备份/时间点恢复 (在服务器中实现,而不是在存储引擎中。) | 是 |
集群数据库支持 | 否 |
聚集索引 | 否 |
压缩数据 | 否 |
数据缓存 | N/A |
加密数据 | 是(在服务器中通过加密函数实现。) |
外键支持 | 否 |
全文搜索索引 | 否 |
地理空间数据类型支持 | 否 |
地理空间索引支持 | 否 |
哈希索引 | 是 |
索引缓存 | N/A |
锁定粒度 | 表 |
MVCC | 否 |
复制支持 (在服务器中实现,而不是在存储引擎中。) | 有限(请参阅本节后面的讨论。) |
存储限制 | RAM |
T 树索引 | 否 |
事务 | 否 |
更新数据字典的统计信息 | 是 |
希望部署使用 MEMORY 存储引擎来存储重要、高可用或频繁更新数据的应用程序的开发人员应考虑 NDB Cluster 是否是更好的选择。MEMORY 引擎的典型用例涉及以下特征
涉及瞬态、非关键数据的操作,例如会话管理或缓存。当 MySQL 服务器停止或重启时,MEMORY 表中的数据会丢失。
用于快速访问和低延迟的内存内存储。数据量可以完全放在内存中,而不会导致操作系统交换虚拟内存页。
只读或主要读取的数据访问模式(有限更新)。
NDB Cluster 提供与 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
表不受存储转换的影响,而内部临时表则会受到影响。
如果内部临时表变得太大,服务器会自动将其转换为磁盘存储,如 Section 10.4.4, “Internal Temporary Table Use in MySQL” 中所述。
用户创建的
MEMORY
表永远不会被转换为磁盘表。
要在 MySQL 服务器启动时填充 MEMORY
表,可以使用 init_file
系统变量。例如,您可以将类似于 INSERT INTO ... SELECT
或 LOAD DATA
的语句放入一个文件中,以从持久数据源加载表,并使用 init_file
来命名该文件。请参阅 Section 7.1.8, “Server System Variables” 和 Section 15.2.9, “LOAD DATA Statement”。
当复制源服务器关闭并重新启动时,其 MEMORY
表将变为空。为了将这种效果复制到副本,源服务器在启动后第一次使用给定的 MEMORY
表时,它会记录一个事件,通知副本必须通过对该表写入 TRUNCATE TABLE
语句来清空表,并将该语句写入二进制日志。当副本服务器关闭并重新启动时,其 MEMORY
表也会变为空,并且它会将其自己的二进制日志写入 TRUNCATE TABLE
语句,该语句将传递给任何下游副本。
当您在复制拓扑中使用 MEMORY
表时,在某些情况下,源服务器上的表和副本上的表可能有所不同。有关处理这些情况的每种情况以防止陈旧读取或错误的信息,请参阅 Section 19.5.1.22, “Replication and MEMORY Tables”。
服务器需要足够的内存来维护所有同时使用的 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
指针大小的精确倍数。在 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 获取。