【问题标题】:Why does TRANSACTION / COMMIT improve performance so much with PHP/MySQL (InnoDB)?为什么 TRANSACTION / COMMIT 使用 PHP/MySQL (InnoDB) 能大幅提升性能?
【发布时间】:2013-01-18 11:14:18
【问题描述】:

我一直在导入大型 CSV 数据文件;通常少于 100,000 条记录。我正在使用 PHP 和 MySQL(InnoDB 表)。我需要在 MySQL INSERTs 之前使用 PHP 转换一些字段并进行一些文本处理(下面代码中 process_note_data() 的一部分)。 MySQL的LOAD DATA不可行,请勿推荐。

我最近尝试通过使用START TRANSACTIONCOMMIT 的MySQL 事务来提高此过程的速度。性能提升令人惊讶。处理时间减少了 20 倍。因此,20 分钟的处理只需要大约 1 分钟。

问题。

1.) 有谁明白为什么会有这样的性能提升(20 分钟到 1 分钟)?

2.) 我是否应该关心 100,000 条记录的交易量有多大?

3.) 我应该关心事务中的大量插入和/或更新吗?

/*
 * Customer Notes Data:
 * Rows are either a meeting, call or note!
 */
$row = 1;
$data = array();
$fields = array();
$line = '';

$db->query('SET autocommit=0;');
$db->query('START TRANSACTION;');

if (($handle = fopen("modules/".$currentModule."/Data/customernote.csv", "r")) !== FALSE) {
  while (($data = fgetcsv($handle, 4096, ',', '"')) !== FALSE && $row < 999000) {
    //Row 1 - CSV header row with field names
    if ($row == 1) {
      $csv_fields = $data;
    } elseif ($row > 1) {
      $fields = $this->process_note_data($data, $csv_fields, $row);
    }
    $row++;
  } // end while
  fclose($handle);
}

$db->query('COMMIT;');
$db->query('SET autocommit=1;');

注意:文本/字段处理在调用$this-&gt;process_note_data() 时完成,然后调用另一个具有INSERT 语句代码的助手类。我没有足够的空间来包含所有代码。 $db-&gt;query() 是 MySQL 查询的典型数据库对象。

【问题讨论】:

  • 我在这里看不到任何更新/插入,也许删除这些会导致执行速度更快;)
  • 文本/字段处理在调用 $this->process_note_data() 中完成,然后调用另一个具有 INSERT 的帮助器类。我没有足够的空间来包含所有代码。请注意,它正在正确插入所有记录。
  • 交易 ~= in memory processing;提交 ~= flush to storage
  • 您不需要(也不应该)SET autocommit=0; 并再次返回;来自here“使用START TRANSACTION,自动提交保持禁用状态,直到您使用COMMIT 或ROLLBACK 结束事务。”

标签: php mysql csv transactions innodb


【解决方案1】:
  1. 请查看此链接:

    https://dev.mysql.com/doc/refman/5.5/en/optimizing-innodb-transaction-management.html

    如果该事务对数据库进行了修改,InnoDB 必须在每次事务提交时将日志刷新到磁盘。当每次更改后都有提交时(与默认的自动提交设置一样),存储设备的 I/O 吞吐量会限制每秒潜在操作的数量。

  2. 大事务可能会影响提交期间的性能(请查看上方)

  3. 仅在回滚的情况下,但可以使用某些设置进行优化(查看链接)

【讨论】:

  • 您是否会建议每 1,000 个左右的 INSERTS 进行 COMMIT 以减少 COMMIT 的处理,还是我对此有点担心?
  • 1k 应该没问题,但这取决于硬件。我建议在这里运行一些测试。无论如何 - 请注意数据一致性(即 - 您加载了 100k 记录中的 20k 并且系统崩溃了)。
  • COMMIT 时间没有太多的处理需要完成,因此没有理由为此定期提交。但是,如果在一个非常大的事务正在进行时系统崩溃,则可能需要大量时间来回滚(这将在服务器启动期间完成,而不接受请求)。只有 100k 行,但是您可能不必担心这一点。
【解决方案2】:

我自己在 .Net 中的小测试(记录 4 个字段):

插入 1 条记录,无事务:60 毫秒

插入 1 条记录,使用事务:158 ms

使用事务插入 200 条记录,在每条记录后提交:17778 毫秒

不使用事务插入 200 条记录:4940 毫秒

使用事务插入 200 条记录,仅在最后一个之后提交 记录:4552毫秒

使用事务插入 1000 条记录,仅在最后一条记录后提交:21795 ms

客户在丹麦,服务器在比利时(Google cloud f1-micro)。

我打算把它放在评论中,但格式不好......所以我提前道歉;-)

【讨论】:

  • 只有 200 条记录,您不会看到太大的差异。拥有超过 100,000 条以上的记录,您应该会开始看到巨大的性能优势。
  • 有趣的使用事务提交位置之间的区别...谢谢!
  • 现在对 SELECT 做同样的测试
猜你喜欢
  • 1970-01-01
  • 2012-03-29
  • 2015-10-17
  • 2018-07-11
  • 2011-04-16
  • 2012-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多