MySQL内存引擎与RAM磁盘上的InnoDB区别

5
我正在编写一款软件,需要将层次结构的数据转换为表格格式。我想要缓存结果几秒钟,并使用SQL进行排序和过滤,而不是每次都在编程语言中完成并提供服务。在使用时,我们需要在这几秒钟内进行400,000次写入和1到2次读取。
每个表格将包含3到15列。每行将包含100字节到2,000字节的数据,尽管在某些情况下,有些行可能会达到15,000字节。如果必要,我可以剪辑数据以保持正常。
我考虑的主要选项是:

MySQL的内存引擎

这是一个很好的选择,几乎专门为我的用例编写!但是,“MEMORY表使用固定长度的行存储格式。变长类型如VARCHAR使用固定长度存储。MEMORY表不能包含BLOB或TEXT列。” - 不幸的是,我确实有长度高达10,000个字符的文本字段,甚至这个数字也没有明确限制。当我循环执行我的展平操作时,我可以根据文本列的最大长度调整varchar长度,但这并不完全优雅。此外,对于我的偶尔出现的15,000个字符行,这是否意味着我需要为数据库中的每一行分配15,000个字符?如果有100,000行,则不包括开销,这是1.3 GB!

在RAMDisk上使用InnoDB

这意味着要在云上运行,并且我可以轻松地启动具有16GB RAM的服务器,配置MySQL以写入tmpfs并使用完整功能的MySQL。我对此担心的是空间。虽然我相信工程师已经编写了内存引擎以防止消耗所有临时存储并使服务器崩溃,但我怀疑这种解决方案是否知道何时停止。当我的2,000字节数据以数据库格式存在时,实际占用多少空间?我该如何监控它?

额外问题

索引 事实上,我将事先知道需要按哪些列进行过滤和排序。我可以在插入之前设置索引,但除了在RAM磁盘上还能获得多少性能增益?索引会增加多少额外开销? 插入 我假设使用一个查询插入多行会更快。但是,这个查询或一系列大型查询都存储在内存中,而我们正在写入内存,因此如果我这样做,我暂时需要双倍的内存。那么我们谈论一次插入一两个或一百个,必须等待完成才能继续处理... InnoDB不锁定表格,但我担心发送两个查询太接近会混淆MySQL。这是一个有效的担忧吗?使用内存引擎时,必须等待完成,因为存在表锁。 临时 除了它们在关闭数据库连接时被删除之外,临时表还有什么好处吗?

你是否排除了使用MyISAM/RAMDisk的原因?听起来你并不需要InnoDB提供的事务语义。 - O. Jones
MyISAM是一种脆弱的存储格式。如果您的服务器在执行大型操作时崩溃或断电,整个表格可能会被破坏。InnoDB具有日志记录功能,可以从几乎任何情况下恢复,通常安全,有时以只读模式运行。 - tadman
你需要将数据放入数据库中,那么你打算用这些数据做什么呢?有时候,如果你只是逐行处理数据,关系型数据库并不是最合适的工具。你可以很容易地将数据缓存到一个平面文件中。 - tadman
听起来你需要的是一个文档存储和解析这些文档的工具。像MongoDB这样的系统可以针对你的文档执行JavaScript函数,以便在需要时进行任何处理。 - tadman
请问您能否编辑您的问题以澄清一些事情?您需要多大程度的并发读写?您说您有15K次写入和1-2次读取。这些读取是否使用某种摘要查询?如果只有表的一部分被写入,进行读取会有什么后果? - O. Jones
显示剩余4条评论
1个回答

2

我建议您使用MyISAM。为您的查询创建适当的索引,然后禁用键、加载表格并启用键。

我建议您为系统制定这样的纪律。我曾经非常有效地使用过类似的纪律。

保留两份表格的副本。将一个称为table_active,第二个称为table_loading

当需要加载新数据时,请使用以下命令。

  ALTER TABLE table_loading DISABLE KEYS;
  /* do your insertions here, to table_loading */
  /* consider using LOAD DATA INFILE if it makes sense.  */
  ALTER TABLE table_loading ENABLE KEYS;  /* this will take a while */
  /* at this point, suspend your software that's reading table_active */
  RENAME TABLE table_active TO table_old;
  RENAME TABLE table_loading TO table_active;
  /* now you can resume running your software */
  TRUNCATE TABLE table_old;
  RENAME TABLE table_old TO table_loading;

另一种方法是使用DROP TABLE table_old;,并创建一个新的表格table_loading,而不是进行最后的重命名操作。

这种双表(双缓冲)策略应该能够很好地工作。它会产生一些延迟,因为读取表格的软件将会使用旧副本。但您将避免从未完全加载的表格中读取。

我建议使用MyISAM,因为您不会耗尽RAM并导致崩溃,并且您不会有固定行长度开销或事务开销。但您也可以考虑MariaDB和Aria存储引擎,它们能够很好地利用RAM缓冲区。

如果您确实使用MEMORY存储引擎,请确保调整您的max_heap_table_size系统变量。如果您的读取查询将使用索引范围扫描(顺序索引访问),请确保指定BTREE样式索引。请参阅此处:http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html


重命名表可能会触发大量磁盘IO,当需要创建基于磁盘的临时表时,这不是最好的方法。如果您使用MEMORY并且您的查询仅使用=,则使用它创建HASH索引将更快,但是如果您使用<=,=,=>的查询,请确保创建BTREE索引。 - Raymond Nijland
如果您在table_active和table_loading两个表中都使用myisam表,则无需暂停。您可以在单个原子操作中交换表:RENAME TABLE table_active to table_old,table_loading to table_active; 它只更新指针,因此应该几乎立即完成,并且它是一个原子操作,因此在交换发生时没有访问表的风险。 - Nathan Stretch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接