最近,我发现MySQL具有一个我不知道的“内存”引擎(我的大部分数据库工作是针对业余项目的,因此我可以随时了解自己的需求)。看来此选项应该可以极大地提高我的性能,所以我想知道它是否有任何缺点。我知道的两个是:


我需要有足够的RAM来容纳有问题的表。
如果计算机关闭,则表将丢失。

我认为#1不会成为问题,因为我使用的是AWS EC2,并且可以根据需要转移到具有更多内存的实例类型。我相信我可以通过根据需要转回到磁盘来缓解#2的问题。

还有什么其他问题?内存引擎能否提供比MyISAM或InnoDB更差的性能?我认为我读到的东西与此引擎的索引有所不同。这是我需要担心的事情吗?

#1 楼

查看http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html上的功能可用性列表,可以跳出两个可能的问题:


没有事务或FK支持,这意味着您将需要在自己的代码中管理事务完整性和引用完整性(最终效率可能比让数据库为您降低效率要低得多,尽管这在很大程度上取决于应用程序的预期的行为模式)。
仅表级锁定:如果您的应用程序需要多个并发写入器写入同一组表,或者在您的读取操作使用锁来确保读取一致的数据的情况下,这可能会严重阻碍可伸缩性-在这种情况下,如果当前在RAM中缓存了足够多的内容,则支持更精细的锁粒度的基于磁盘的表的性能会好得多。

除此之外,假设您有足够的RAM,则基于内存表应该比基于磁盘的表快。显然,您需要考虑将快照拍摄到磁盘上以解决服务器实例重置时发生的问题,如果数据需要经常捕获(如果您可能会损失一天的时间),则这可能完全抵消总体性能优势。在这种情况下,您每天只能备份一次,但是在大多数情况下是不可接受的。)

替代方法可能是:


使用基于磁盘的表,但要确保您有足够的RAM在任何给定时间将它们全部保存在RAM中(并且“足够的RAM”可能比您认为的要多,因为您需要考虑计算机上的任何其他进程,OS IO缓冲区/高速缓存等)
在每次启动时扫描表的全部内容(所有数据和索引页),以将每个表的SELECT * FROM <table> ORDER BY <pkey fields>和随后的每个索引SELECT <indexed fields> FROM <table> ORDER BY <index fields>的内容预加载到内存中

这样,所有数据都在RAM中,您只需担心写入操作的I / O性能。如果您的应用程序的通用工作集比整个数据库小(通常是这种情况-在大多数应用程序中,大多数用户只会在最近的时间查看最新数据),所以最好选择更多的数据您可以扫描以将其预加载到内存中,从而允许其余磁盘按需从磁盘加载。

评论


为什么您需要内存数据库的事务完整性?如果电源关闭,则无论如何您将失去一切。

–osa
2014年12月6日下午6:33

@osa:假设它允许并发访问而不是序列化所有内容,那么您将需要某种形式的完整性管理。

– David Spillett
2014年12月6日在21:27

#2 楼

在很多情况下,不使用内存存储引擎-以及何时使用InnoDB会更快。您只需要考虑并发性,而不是琐碎的单线程测试。

如果您有足够大的缓冲池,那么InnoDB也将完全驻留于读取操作的内存中。数据库具有缓存。它们使自己热身!

而且-不要低估行级锁定和MVCC的价值(读者不会阻止作者)。当写入必须持续到磁盘时,它可能会“变慢”。但是至少在写操作期间不会像在内存表上那样阻塞(没有MVCC;表级锁定)。

#3 楼

作为记录。我在内存中测试了Mysql表以存储一些信息。而且我测试了PHP的APC(APCu)来存储相同的信息。

用于58000个注册表。 (varchar +整数+日期)。



文本格式(csv格式)的原始信息为24mb。
PHP的APC使用44.7mb的RAM。
Mysql的表使用575mb RAM。

该表只有一个索引,因此我不认为这是主要因素。

结论:

内存表不是“大”表的选项,因为它使用了过多的内存。

评论


这是一个过于简单的答案。可以通过使用较小的数据类型,将BTREE明确定义为索引类型并限制加载到RAM中的数据量来调整MEMORY存储引擎。对于较小的集合,它仍然是可行的选择。还有其他因素,例如主动磁盘I / O。参见我的帖子dba.stackexchange.com/questions/6156/…和dba.stackexchange.com/questions/2868/…)

– RolandoMySQLDBA
2014年6月2日在21:46



实际上,我检查过更改索引(甚至完全删除了索引),并且大小没有太大变化(包括从头开始重建表)。恕我直言,Mysql在幕后做了一些事情,可能是某种优化或在每列中分配最大大小(例如varchar)。

–麦哲伦
2014年6月3日于1:05

原因几乎可以肯定是由于您的VARCHAR:“ MEMORY表使用固定长度的行存储格式。可变长度类型(例如VARCHAR)使用固定长度存储。” dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html实际上,VARCHAR在MEMORY引擎中看起来像是CHAR。

–马修1471
2014年7月6日20:17



#4 楼

基于MEMORY的表的另一个缺点是它们不能在同一查询中多次引用。至少在v5.4之前发现了该行为。对于CTE(从v8.x版本开始),无需使用基于内存的中间表来处理复杂的过程。

#5 楼

根据MySQL和MariaDB手册,MEMORY存储不支持BLOB和CLOB(各种TEXT类型)。出于我们自己的目的,这使MEMORY存储引擎几乎无用。

http://dev.mysql.com/doc/refman/5.7/zh-CN/memory-storage-engine.html


MEMORY表不能包含BLOB或TEXT列。


https://mariadb.com/kb/zh-CN/mariadb/memory-storage-engine/


可变长度类型,例如VARCHAR可以在MEMORY表中使用。 MEMORY表不支持BLOB或TEXT列。


仅尝试将部分数据库转换为MEMORY存储时,我发现不支持存储间引擎外键。因此,所有应该包含表外键引用的表(包含BLOB / CLOB)也应该属于非内存存储类型(至少,这会影响InnoDB子表)。

#6 楼

MEMORY表不用于持久性存储,尤其是大数据子集或对保留至关重要的任何事物。根据我的经验,它们的最佳目的是在复杂过程中创建和填充临时表期间存放瞬态记录,如果您将引擎的关键缓冲区阈值设置得足够高而不会引起这种情况,则此表的执行速度将比大多数其他表类型快得多。磁盘写入。为此,由于没有磁盘I / O,因此它可以比MyISAM或InnoDB快一个数量级,并且在一个表封装在特定过程中的情况下,索引和关系的重要性不如它们将在需要持久性的地方。

#7 楼

除了以前的答案。直接来自MySQL 5.7手册:

“ MEMORY性能受到单线程执行和处理更新时表锁开销导致的争用的限制。这会限制负载增加时的可伸缩性,尤其是对于包含写操作的语句混合。”

...这是一个非常实际的限制。例如:当您有多个会话试图创建快速的MEMORY临时表时,单线程可能会导致严重的性能瓶颈。