我最近发现 MySQL 有一个我不知道的“内存”引擎(我的大部分数据库工作都是针对业余项目,所以我会边走边学)。看起来这个选项应该会给我带来极大的性能提升,所以我想知道它是否有任何缺点。我知道的两个是:
- 我需要有足够的 RAM 来保存有问题的表。
- 如果机器关闭,表格将丢失。
我相信 #1 应该不是问题,因为我使用的是 AWS EC2,并且可以根据需要迁移到具有更多内存的实例类型。我相信我可以通过根据需要转储回磁盘来缓解 #2。
还有哪些其他问题?内存引擎能否提供比 MyISAM 或 InnoDB 更差的性能?我想我读到了这个引擎的索引不同的东西;这是我需要担心的事情吗?
查看http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html上的功能可用性列表,会跳出两个可能的问题:
除此之外,假设您有足够的 RAM,基于内存的表应该比基于磁盘的表快。显然,您需要考虑将快照保存到磁盘以解决重置服务器实例时发生的问题,如果需要经常捕获数据,这可能会完全否定整体性能优势(如果您可以忍受失去一天在这种情况下,您可以每天备份一次数据,但在大多数情况下这是不可接受的)。
一种替代方法可能是:
SELECT * FROM <table> ORDER BY <pkey fields>
然后是每个表,然后是SELECT <indexed fields> FROM <table> ORDER BY <index fields>
每个索引这样,您的所有数据都在 RAM 中,您只需要担心写入操作的 I/O 性能。如果您的应用程序的通用工作集比整个数据库小得多(通常是这种情况 - 在大多数应用程序中,大多数用户只会在最长时间内查看最新数据),您可能会更好地选择多少您扫描预加载到内存中,允许按需从磁盘加载其余部分。
有很多情况下不使用内存存储引擎——而 InnoDB 什么时候会更快。您只需要考虑并发性,而不是简单的单线程测试。
如果你有足够大的缓冲池,那么 InnoDB 也将完全驻留在内存中用于读取操作。数据库有缓存。他们让自己暖和起来!
另外——不要低估行级锁定和MVCC的价值(读者不会阻止写者)。当写入必须持续到磁盘时,它可能会“更慢”。但至少在写入操作期间您不会像在内存表上那样阻塞(没有 MVCC;表级锁定)。
作为记录。我在内存中测试了 Mysql 表以存储一些信息。我测试了 PHP 的 APC (APCu) 以存储相同的信息。
对于 58000 个注册表。(varchar + 整数 + 日期)。
该表只有一个索引,所以我不认为它是主要因素。
结论:
内存表不是“大”表的选项,因为它使用了太多内存。
基于 MEMORY 的表的另一个缺点是它们不能在同一个查询中被多次引用。至少在 v5.4 之前发现了这种行为。如何使用 CTE(自 v8.x 起)无需为复杂的过程使用基于 mem 的中间表。
根据 MySQL 和 MariaDB 手册,MEMORY 存储不支持 BLOB 和 CLOB(各种 TEXT 类型)。出于我们自己的目的,这使得 MEMORY 存储引擎几乎毫无用处。
http://dev.mysql.com/doc/refman/5.7/en/memory-storage-engine.html
https://mariadb.com/kb/en/mariadb/memory-storage-engine/
在尝试仅将部分数据库转换为 MEMORY 存储时,我发现不支持跨存储引擎外键。因此,所有应该具有对表的外键引用的表,包含 BLOB/CLOB 也应该是非内存存储类型(至少,这会影响 InnoDB 子表)。
MEMORY 表不适用于持久存储,尤其是大型数据子集或保留至关重要的任何内容。根据我的经验,它们的最佳目的是在复杂过程期间在临时表的创建和填充期间保存临时记录,如果您将引擎的关键缓冲区阈值设置得足够高而不会产生磁盘写入。为此目的,这可以比 MyISAM 或 InnoDB 快一个数量级,因为没有磁盘 I/O,并且对于封装在特定过程中的表,索引和关系并不像它们那么重要将在预期持久性的地方。
除了前面的答案。直接来自 MySQL 5.7 手册:
“内存性能受到单线程执行和处理更新时表锁开销导致的争用的限制。这限制了负载增加时的可伸缩性,特别是对于包含写入的语句混合。”
...这是一个非常现实的限制。例如:当您有多个会话试图创建良好的快速 MEMORY 临时表时,单线程可能会导致严重的性能瓶颈。