本文首发于 2019-04-22 20:56:52
可能有的朋友对MEMORY存储引擎不太了解,首先介绍一下(以下描述来自官方):
hash索引
(也支持B-Tree索引),因此Memory类型的表访问速度非常快(比使用B-Tree索引的MyISAM表快),但是一旦服务关闭,表中的数据就会丢失
。--init-file
选项,把类似insert into ... select
或load data
的语句放进去。 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)
现象:
最近碰到有用户使用 MEMORY 存储引擎,引发主从 GTID 不一致、从节点 GTID 比主节点多一条的情况。
分析:
主节点有 prepare 的事务然后故障(从节点变为主)、重启导致 local commit
的情况。DELETE FROM
。向用户反馈问题原因后,用户将 MEMORY 表改为了 InnoDB 表。
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
语句,这条语句会复制到从节点,以达到主从数据一致的目的。
PS:不想看过程的朋友,请跳到最后看总结。
举例来说,集群有三个节点A、B、C,节点A为主节点。
情形一:MEMORY 表有数据的情况下,重启主节点、触发主从切换:
MEMORY
表 mdb.t1
,执行 insert into mdb.t1 values(1,1),(2,2),(3,3),(4,4)
插入一些数据。mysql> select * from mdb.t1; Empty set (0.00 sec)
mysql> select * from mdb.t1; +------+------+ | a | b | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 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 表无数据的情况下,重启主节点、触发主从切换:
uuid_a:1-11
这条事务,三个节点的 mdb.t1
数据为空。DELETE FROM
事务 uuid_b:1-12
。情形三:MEMORY 表无数据的情况下,重启从节点:
uuid_a:1-12
这条事务DELETE FROM
事务 uuid_a:1-13
。情形四:MEMORY 表有数据的情况下,重启从节点:
uuid_a:1-13
。INSERT
语句向 mdb.t1
插入一些数据,三个节点 GTID 为 uuid_a:1-14
。DELETE FROM
事务 uuid_b:1
。DELETE FROM
事务。SELECT
)MEMORY 表,才会触发生成 DELETE FROM
。在生产环境中千万不要使用MEMORY存储引擎
。欢迎关注我的微信公众号【MySQL数据库技术】。
标题 | 网址 |
---|---|
GitHub | https://dbkernel.github.io |
知乎 | https://www.zhihu.com/people/dbkernel/posts |
思否(SegmentFault) | https://segmentfault.com/u/dbkernel |
掘金 | https://juejin.im/user/5e9d3ed251882538083fed1f/posts |
开源中国(oschina) | https://my.oschina.net/dbkernel |
博客园(cnblogs) | https://www.cnblogs.com/dbkernel |