本文首发于 2019-04-22 20:56:52
1. MEMORY 引擎简介
可能有的敌人对 MEMORY 存储引擎不太理解,首先介绍一下(以下形容来自官网):
- MEMROY 存储引擎(以前称为 HEAP)的表 把表构造寄存到磁盘上,而把数据放在内存中。
- 每个 Memory 表只理论对应一个磁盘文件,在磁盘中体现为.frm 文件。因为它的数据是放在内存中的,并且默认应用
hash 索引
(也反对 B -Tree 索引),因而 Memory 类型的表访问速度十分快(比应用 B -Tree 索引的 MyISAM 表快),然而一旦服务敞开,表中的数据就会失落
。 - 因为 MEMRORY 表在 mysqld 重启后数据会失落,为了取得稳固的数据源,能够在启动 mysqld 时增加
--init-file
选项,把相似insert into ... select
或load data
的语句放进去。 -
MEMROY 存储引擎的典型实用场景蕴含如下特色:
- 波及瞬态非关键数据的操作,如会话治理或缓存。
- 数据能够齐全放入内存而不会导致操作系统替换虚拟内存页,并且要求快速访问。
- 只读或以读为主的数据拜访模式(无限的更新)。
-
对于性能:
- 在解决更新时,单线程执行和表锁开销导致的争用会限度 MEMORY 性能。
- 只管 MEMORY 表在内存中进行解决,然而对于忙碌的服务器、通用查问或读 / 写工作负载,它们并不一定比 InnoDB 表快。特地是,执行更新所波及的表锁定会升高多个会话中内存表的并发应用速度。
-
MEMORY 表具备以下特色:
- MEMORY 表的空间以小块模式调配。表对插入应用 100% 动静哈希,不须要占用额定的内存。
- 被删除的行并未开释,而是放在链表中,并在插入新数据时重用。
- MEMORY 表应用固定长度的行存储数据。(即便是 VARCHAR 也不例外)
- MEMORY 表不反对 BLOB、TEXT 列。
- MEMORY 表反对 AUTO_INCREMENT 列。
- MEMORY 表是有大小限度的,次要受限于两个参数:
max_heap_table_size
和MAX_ROWS
(默认状况下MAX_ROWS
依赖于max_heap_table_size
,可执行ALTER TABLE tbl_name MAX_ROWS= MAX_ROWS
批改MAX_ROWS
)。
问:MEMORY 表和长期表有什么区别?
- 长期表默认应用的存储引擎是服务器指定的存储引擎(对于 5.7 是 InnoDB),因为长期表定义和数据都放在内存中,未放到磁盘,因而用
show tables
招不到长期表。- 如果长期表占用空间太大,MySQL 会将其转为磁盘存储。而对于用户创立的 MEMORY 表,则不会转为磁盘存储。
mysql> create temporary table temp_t1(a int primary key, b int);
Query OK, 0 rows affected (0.00 sec)
mysql> show tables;
+---------------+
| Tables_in_db4 |
+---------------+
| t1 |
+---------------+
1 row in set (0.00 sec)
2. 故障剖析
景象:
最近碰到有用户应用 MEMORY 存储引擎,引发主从 GTID 不统一、从节点 GTID 比主节点多一条的状况。
剖析:
- 查看日志,确认没有产生过主从切换,也就排除了
主节点有 prepare 的事务而后故障(从节点变为主)、重启导致 local commit
的状况。 - 在从节点 binlog 中找到那条本地事务,发现是 MEMORY 表的
DELETE FROM
。 - 该从节点产生过重启,依据 MEMORY 引擎的个性,确认是 MEMORY 表生成的。
向用户反馈问题起因后,用户将 MEMORY 表改为了 InnoDB 表。
3. 疑难
3.1. 何时生成 DELETE FROM
?
A server’s
MEMORY
tables become empty when it is shut down and restarted. If the server is a replication master, its slaves are not aware that these tables have become empty, so you see out-of-date content if you select data from the tables on the slaves. To synchronize master and slaveMEMORY
tables, when aMEMORY
table is used on a master for the first time since it was started, aDELETE
statement is written to the master’s binary log, to empty the table on the slaves also. The slave still has outdated data in the table during the interval between the master’s restart and its first use of the table. To avoid this interval when a direct query to the slave could return stale data, use the--init-file
option to populate theMEMORY
table on the master at startup.
这段形容的含意是:
- 服务器的 MEMORY 表在敞开和重新启动时会变为空。
- 为了避免主服务器重启、从服务器未重启导致从服务器上有过期的 MEMORY 表数据,会在重启服务器时向 binlog 写入一条
DELETE FROM
语句,这条语句会复制到从节点,以达到主从数据统一的目标。
3.2. 对于主从复制的 MySQL 集群,主或从故障重启有什么问题?
PS:不想看过程的敌人,请跳到最初看总结。
举例来说,集群有三个节点 A、B、C,节点 A 为主节点。
情景一:MEMORY 表有数据的状况下,重启主节点、触发主从切换:
- 创立
MEMORY
表mdb.t1
,执行insert into mdb.t1 values(1,1),(2,2),(3,3),(4,4)
插入一些数据。 - 敞开节点 A 的 MySQL,节点 B 变为主,之后节点 A 以从节点启动,此时:
-
节点 A 无数据:
mysql> select * from mdb.t1; Empty set (0.00 sec)
-
节点 B、C 有数据:
mysql> select * from mdb.t1; +------+------+ | a | b | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 |
-
rows in set (0.00 sec)
并且,节点 A 的 GTID 为 `uuid_a:1-11`,节点 B、C 的 GTID 为 `uuid_a:1-10`,节点 A 的 binlog 比另外两个节点多一条 `DELTE FROM mdb.t1`。
情景二:MEMORY 表无数据的状况下,重启主节点、触发主从切换:
- 将节点 A 切换为主节点,节点 B、C 同步了
uuid_a:1-11
这条事务,三个节点的mdb.t1
数据为空。 - 敞开节点 A 的 MySQL,节点 B 变为主,之后节点 A 以从节点启动,此时,节点 A 生成了一条本地
DELETE FROM
事务uuid_b:1-12
。
情景三:MEMORY 表无数据的状况下,重启从节点:
- 将节点 A 切换为主节点,节点 B、C 同步了
uuid_a:1-12
这条事务 - 重启节点 A 的 MySQL,节点 A 生成一条本地
DELETE FROM
事务uuid_a:1-13
。
情景四:MEMORY 表有数据的状况下,重启从节点:
- 将节点 A 切换为主节点,另外两个节点同步节点 A 的本地事务,三个节点 GTID 为
uuid_a:1-13
。 - 执行
INSERT
语句向mdb.t1
插入一些数据,三个节点 GTID 为uuid_a:1-14
。 - 重启节点 B,其生成了一条本地
DELETE FROM
事务uuid_b:1
。
3.3. 总结
- 测试发现,无论什么状况下,MEMORY 存储引擎都会生成一条本地
DELETE FROM
事务。 - 在某些状况下,必须被动拜访(比方
SELECT
)MEMORY 表,才会触发生成DELETE FROM
。 - 最重要的一点,
在生产环境中千万不要应用 MEMORY 存储引擎
。
欢送关注我的微信公众号【数据库内核】:分享支流开源数据库和存储引擎相干技术。
题目 | 网址 |
---|---|
GitHub | https://dbkernel.github.io |
知乎 | https://www.zhihu.com/people/… |
思否(SegmentFault) | https://segmentfault.com/u/db… |
掘金 | https://juejin.im/user/5e9d3e… |
开源中国(oschina) | https://my.oschina.net/dbkernel |
博客园(cnblogs) | https://www.cnblogs.com/dbkernel |