当前位置: 首页 > 科技观察

MySQLMEMORY引擎与性能对比

时间:2023-03-12 19:09:25 科技观察

同事详细咨询MySQLMEMORY引擎,是否能满足需求。没有太多的了解,这里做一个系统的总结。MEMORY存储引擎创建的表数据只能存储在内存中。MySQL宕机、硬件故障或意外断电都会导致MEMORY引擎表中的数据丢失。因此,MEMORY表中的数据来自于其他表(可以永久保存在磁盘上),用于只读应用,或者用于实现数据周转的临时工作。MEMORY存储引擎特性[a]在服务器中实现(通过加密功能)。静态数据表空间加密在MySQL5.7及更高版本中可用。[b]在服务器中实现,而不是在存储引擎中。[c]在服务器中实现,而不是在存储引擎中实现。来源:https://dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html何时使用MEMORY临时使用,不重要的数据,例如网站的会话管理和缓存。数据丢失是可以接受的。利用其快速访问和低延迟功能。只读或以读为主的操作不适合大量的写操作。性能特征Memtables受到表级锁引起的单线程执行和争用的限制。当负载增加时限制可伸缩性,尤其是对于写操作。内存表虽然是在内存中处理的,但是在繁忙的服务网络上,比如一般的查询或者读写场景,不一定比InnoDB表快。特别是,执行更新操作的多个会话可能会导致性能不佳。根据不同的SQL查询,需要创建内存表默认的哈希索引(基于唯一键的单值查询),或者B树索引(等值查询、不等值查询或范围查询)。内存表的物理特性每个内存表都会在硬盘上创建一个文件来保存表结构(无数据)。文件名以内存表名开头,以.frm结尾。特点内存表空间使用小块。该表使用100%动态哈希插入。删除的行放在空闲列表中,下次插入新数据时会用到。使用固定长度的行存储格式。变长类型存入内存表时需要转换为定长类型。不支持BLOB和TEXT类型的列。内存表支持自增列(AUTO_INCREMENT)临时表不能跨多个会话共享。内存表的DDL操作创建临时表CREATETABLEt(iINT)ENGINE=MEMORY;基于非内存表创建内存表,并将数据拉入内存表FROMtest;mysql>DROPTABLEtest;内存表的最大大小受max_heap_table_size参数限制,默认为16MB。您需要根据场景调整此参数。索引MEMORY存储引擎支持HASH和BTREE索引。创建TABLELookup(idINT,INDEXUSINGHASH(id))引擎=内存;CREATETABLELookup(idINT,INDEXUSINGBTREE(id))引擎=内存;每个内存表可以创建64个索引,每个索引最多支持16列,一个key的长度最大为3072bytes。如果一个内存表哈希索引的键值重复度很高,更新键值和删除操作的速度会明显降低。这种减速与键值重复的程度成正比。您可以使用BTREE索引来避免此问题。Memtables可以有非唯一的键(这是哈希索引的一个不常见的特性)。索引列可以包含NULL值。加载数据MySQL启动时,添加--init-file选项,在该文件中添加如下命令,保证启动后内存表中有数据。INSERTINTO...SELECTLOADDATAINFILE内存表和复制(Replication)服务器重启会导致内存表数据丢失。如果是主库,从库并没有意识到主库表中的数据被删除了,所以从库看到的是过期数据。重启后,主从库如何同步内存表数据?当主库使用内存表时,主库启动后,会在主库的二进制日志中写入一条DELETE语句,收到命令后从库中清除内存表。主库重启过程中,从库仍然读取过期数据。为了避免这种情况,在主库启动的时候加上--init-file参数,让主库启动自动加载数据到内存表中。(官方文档写得不严谨,我觉得仅限于内存表的只读场景,如果不是只读,即使加上了--init-file参数,内存中的数据不能保证主库的表)。管理内存使用服务器必须有足够的内存来满足多个内存表的使用。如果从memtable中删除个别行,则不会回收内存。当整个内存表被删除时,内存被回收。在同一个内存表中,之前删除的行占用的空间会被新的行重用。执行DELETE和TRUNCATETABLE释放内存表占用的空间。如果该表未在使用中,您可以使用DROPTABLE命令。要释放in-memory表占用的内存,可以使用ALTERTABLEXXENGINE=MEMORY强制重建表。计算内存表中1行记录占用内存的计算公式为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指针大小的精确倍数。sizeof(char*)在32位机器上为4,在64位机器上为8。如前所述,max_heap_table_size系统变量决定了memtable的最大大小。在创建内存之前可以设置这个变量来控制每个memtable的最大大小。(不建议修改全局max_heap_table_size的大小,否则所有会话的内存表的最大大小都会是这个值)。下面的例子创建了2个最大大小为1M和2M的内存表sec)mysql>SETmax_heap_table_size=1024*1024*2;QueryOK,0rowsaffected(0.00sec)mysql>CREATETABLEt2(idINT,UNIQUE(id))ENGINE=MEMORY;QueryOK,0rowsaffected(0.00sec)服务器重启后,每个表的大小都变成全局max_heap_table_size变量的值大小。压测结果通过了sysbench压测。InnoDB的写性能完全超过MEMORY引擎,MEMORY的读性能略高于InnoDB。InnoDB整体性能比较好,日常使用足够了。考虑到MEMORY引擎雷点太多,建议不要使用MEMORY引擎。