【问题标题】:InnoDB vs. MyISAM insert query timeInnoDB vs. MyISAM 插入查询时间
【发布时间】:2011-11-05 06:13:37
【问题描述】:

我有一个大型 MySQL 表(约 1000 万行,6.5G),用于读写。它是 MyISAM,由于 MyISAM 在写入时的所有表锁,我得到了很多锁。

我决定尝试迁移到推荐用于读/写表的 InnoDB,它只锁定写入时的特定行。

转换后,我测试了插入语句,结果发现 InnoDB 表中的插入语句是 MyISAM 表中的大约 15 倍(从 0.1 秒到 1.5 秒)。这是为什么呢?

我还没有为 InnoDB 配置任何东西,并且还计划添加分区,但是这个数字对我来说仍然是出乎意料的。当然表是相同的,相同的索引等。

根据要求提供的其他信息:

2 个索引。 primary 是 Big INT 类型的 data_id,以及 varchar(255) 类型的非唯一 user_id。

插入共有约 150 行,具有相同的 user_id。

索引大小:MyISAM 200 MB,InnoDB 400MB

【问题讨论】:

  • 你能给我们看看索引吗?这是导致插入时间长的最可能原因。
  • 我有 2 个索引,data_id 是主键,user_id 不是唯一的。我的插入共有约 150 行,它们具有相同的 user_id(具有索引)。
  • 但是每个索引的内容是什么?如果有一堆 blob,那么肯定会很难索引。但如果它们是整数或其他微不足道的类型,那么就更难理解为什么性能会变差了。
  • 对不起。 user_id 是 varchar(255),data_id 是 Big INT。表中没有斑点
  • @normalppl - 有没有办法提供一个示例数据库和代码来演示您的问题?

标签: mysql database optimization innodb myisam


【解决方案1】:

首先,你的测试无效,因为当你有并发时,行级锁定相对于表级锁定的速度增益来了!只有 1 个线程进行插入,在这两种情况下,每次插入都有 1 个锁定/解锁,并且插入不会等待表级锁定被释放。

其次,正如 JIStone 所说,当表大小大于缓冲池时,非顺序主键是插入的性能杀手。

第三,缓冲池大小是 InnoDB 中最重要的设置之一。使其尽可能简单(推荐设置为可用 RAM 的 80%)。

接下来,正如@wallyk 所述,innodb_flush_log_at_trx_commit 对 I/O 操作的速度起着至关重要的作用。

接下来,innodb_log_file_size 和 innodb_buffer_file_size 很重要。

接下来,请记住,由于您有 2 个唯一索引,因此在 InnoDB 插入行之前,它必须检查索引中是否存在该值,并且您的索引很大。

没有关于表和索引的详细信息,我不能给你更多的建议,但请记住,没有存储引擎是万能的,虽然通常你可以通过简单地改变存储引擎来获得很多速度,添加索引或调整一个变量,在大规模系统中,事情比这更复杂。但是,正如我所说,您不应该在孤立的测试中比较原始插入速度,您必须使您的测试尽可能接近实际应用程序。

更新:另一个提示 在 MyISAM 和 InnoDB 中,multi-insert (insert into .... values(...),(...),(...)) 更快。此外,在 InnoDB 中,您可以在事务中进行插入,这会在事务完成之前禁用更新非唯一索引,而且速度也更快(但不要执行大型事务,因为使用的隔离级别实际上会减慢速度,并且行版本控制的工作方式)。

【讨论】:

    【解决方案2】:

    我认为,InnoDB 实现了一个真正的 ACID,并且做了很多fsync()s 来保存数据。而且 MyISAM 不是真正的 ACID,而且 fsync() 的作用更少。

    There are recomendations to kill fsync当你需要加载大量数据时

    If you want to load data into InnoDB quickly:
    * use as large an InnoDB buffer cache as possible
    * make the InnoDB log files as large as possible
    * minimize the number of unique indexes on your tables
    * disable all calls to fsync from InnoDB. You have to hack the code to
    get this, or look at the Google patch. Of course, you only want to run
    in this mode when loading the table.
    

    And lists says:

    MyISAM 始终运行 在“nosync”模式下,也就是说,它从不调用 fsync() 将文件刷新到 磁盘。

    InnoDB 的 nosync 在测试某些操作系统/计算机是否非常慢时很有用 在 fsync() 中。但它不应该在生产系统中使用。

    同样的消息说,InnoDB 有时使用另一种同步方法:

    然后 InnoDB 使用 fsync() 刷新数据和日志文件。如果 O_DSYNC 是 指定,InnoDB 使用 O_SYNC 打开和刷新日志文件,但使用 fsync() 刷新数据文件。如果指定了 O_DIRECT(在某些 Linux 版本从 MySQL-4.0.14 开始),InnoDB 使用 O_DIRECT 打开 数据文件,并使用 fsync() 刷新数据和日志文件。注意 InnoDB 不使用 fdatasync() 或 O_DSYNC 因为有问题 在许多 Unix 风格上使用它们。

    【讨论】:

      【解决方案3】:

      记住 InnoDB 处理键的方式可能会导致麻烦。由于所有内容都按照具有非自动增量主键的主键的顺序存储在磁盘上,因此可能会导致大部分表通过任何插入在磁盘上移动(当我有一个数据透视表并使用时,我遇到了这个问题组合的 id 作为主键)。在磁盘上移动数据很慢。

      此外,InnoDB 的索引大小可以更大,因为每个索引还包含主键。检查以确保您没有遇到任何内存限制。

      【讨论】:

      • 我没想到它会更快,我意识到它应该有助于许多读\写。但是,如果我通常执行的基本插入需要 15 倍以上(从 0.1 秒到 1.5 秒),那听起来好像不太好,不是吗?
      • 是的,抱歉,读取为 15% 而不是 15x - 可能存在一些问题
      【解决方案4】:

      related answer 建议将 innodb_flush_log_at_trx_commit 变量设置为 2 可能会在写入与读取的比率相对较高时提高性能。请参阅the documentation 了解更多信息。

      【讨论】:

      • 我现在只是在测试。所以没有读取,只有一个 150 行的插入,想先弄清楚这个。
      • 这对我产生了巨大的影响。在不更改 innodb_flush_log_at_trx_commit 的情况下插入 7500 行需要 5 分钟。将其更改为 0 或 2 将相同的 INSERT 减少到 3 秒。
      猜你喜欢
      • 2012-05-15
      • 2011-10-28
      • 2011-10-17
      • 2012-03-01
      • 2011-07-25
      • 2016-11-10
      • 2013-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多