第15章:存储引擎和表类型 / 15.4. MEMORY (HEAP)存储引擎

MEMORY存储引擎用存在内存中的内容来创建表。这些在以前被认识为HEAP表。MEMORY是一个首选的术语,虽然为向下兼容,HEAP依旧被支持。

每个MEMORY表和一个磁盘文件关联起来。文件名由表的名字开始,并且由一个.frm的扩展名来指明它存储的表定义。

要明确指出你想要一个MEMORY表,可使用ENGINE选项来指定:

CREATE TABLE t (i INT) ENGINE = MEMORY;

如它们名字所指明的,MEMORY表被存储在内存中,且默认使用哈希索引。这使得它们非常快,并且对创建临时表非常有用。可是,当服务器关闭之时,所有存储在MEMORY表里的数据被丢失。因为表的定义被存在磁盘上的.frm文件中,所以表自身继续存在,在服务器重启动时它们是空的。

这个例子显示你如何可以创建,使用并删除一个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表有下列特征:

·         给MEMORY表的空间被以小块来分配。表对插入使用100%动态哈希来。不需要溢出区或额外键空间。自由列表无额外的空间需求。已删除的行被放在一个以链接的列表里,并且在你往表里插入新数据之时被重新使用。MEMORY表也没有通常与在哈希表中删除加插入相关的问题。

·         MEMORY表可以有多达每个表32个索引,每个索引16列,以及500字节的最大 键长度。

·         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树的一般特征和哈希索引在7.4.5节,“MySQL如何使用索引”里描述。

·         你可以在一个MEMORY表中有非唯一键。(对哈希索引的实现,这是一个不常用的功能)。

·         你页可以对MEMORY表使用INSERT DELAYED。请参阅13.2.4.2节,“INSERT DELAYED语法”

·         如果你在一个有高度键重复的(许多索引条目包含同一个值)MEMORY表上有一个哈希索引,对影响键值的表的更新及所有删除都是明显地慢的。这个变慢的程度比例于重复的程度(或者反比于索引cardinality)。你可以使用一个B树索引来避免这个问题。

·         MEMORY表使用一个固定的记录长度格式。

·         MEMORY不支持BLOB或TEXT列。

·         MEMORY支持AUTO_INCREMENT列和对可包含NULL值的 列的索引。

·         MEMORY表在所有客户端之间共享(就像其它任何非TEMPORARY表)。

·         MEMORY表内容被存在内存中,内存是MEMORY表和服务器在查询处理之时的空闲中创建的内部表共享。可是,两个类型的表不同在于MEMORY表不会遇到存储转换,而内部表是:

-        如果一个内部表变得太大,服务器自动把它转换为一个磁盘表。尺寸限制由tmp_table_size系统变量的值来确定。

-        MEMORY表决不会转换成磁盘表。要确保你不会偶尔做点傻事,你可以设置max_heap_table_size系统变量给MEMORY表加以最大尺寸。对于单个的表,你也可以在CREATE TABLE语句中指定一个MAX_ROWS表选项。

·         服务器需要足够内存来维持所有在同一时间使用的MEMORY表。

·         当你不再需要MEMORY表的内容之时,要释放被MEMORY表使用的内存,你应该执行DELETE FROM或TRUNCATE TABLE,或者整个地删除表(使用DROP TABLE)。

·         当MySQL服务器启动时,如果你想开拓MEMORY表,你可以使用--init-file选项。例如,你可以把INSERT INTO ... SELECT 或LOAD DATA INFILE这样的语句放入这个文件中以便从持久稳固的的数据源装载表。请参阅5.3.1节,“mysqld 命令行选项” and 13.2.5节,“LOAD DATA INFILE 语法”

·         如果你正使用复制,当主服务器被关闭且重启动之时,主服务器的MEMORY表变空。可是从服务器意识不到这些表已经变空,所以如果你从它们选择数据,它就返回过时的内容。自从服务器启动后,当一个MEMORY表在主服务器上第一次被使用之时,一个DELETE FROM语句被自动写进主服务器的二进制日志,因此再次让从服务器与主服务器同步。注意,即使使用这个策略,在主服务器的重启和它第一次使用该表之间的间隔中,从服务器仍旧在表中有过时数据。可是,如果你使用--init-file选项于主服务器启动之时在其上推行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()代表round-up因子,它使得行的长度为char指针大小的确切倍数。sizeof(char*)在32位机器上是4,在64位机器上是8。

对于MEMORY存储引擎,在http://forums.mysql.com/list.php?92上有一个专门的论坛。