15.6.1.5-将MyISAM表转换为InnoDB表:太长或太短事务的处理

因为MyISAM表不支持事务,所以你可能不太关注autocommit设置,以及commit和rollback语句。这些关键词对并发读写InnoDB表来说非常重要,它们在高写负载 场景下提供了大量显而易见的好处。

在开启一个事务时,系统保持了该事务开始时所见的数据的快照,这在事务中插入、更新、删除大量的记录时,可能会导致系统负载增加。因此,我们应该小心翼翼,避免 事务执行时间过长:

  • 如果你在一个mysql会话中做交互式测试,记得在结束时提交(持久化变更)或回滚(回滚变更)。及时关闭活跃的会话,不要让他们长时间处于空闲状态,这样可以避 免有时使事务长时间处于开启状态。

  • 确保在应用程序中的错误处理代码中,要即使回滚未完成的变更,或者提交已完成的变更。

  • 回滚是一个相对来说代价高昂的操作。因为insert、update和delete操作在commit之前就写入InnoDB表了,这主要是因为大部分修改都会被成功提交,rollback很 少见。在处理大量数据时,要避免修改了很多记录,然后又进行回滚。

  • 如果是连续插入大量的数据,记得周期性的进行提交操作,这样可以避免事务执行时间过长。在存储数据的典型场景下,如果发生了某些错误,我们truncate表,然后重新操作 都比ROLLBACK更好。

上面的一些建议可以避免长事务,节约内存和磁盘空间。如果事务非常非常小,可能会带来新的问题,那就是I/O成本过高。因为每一次commit时,MySQL都要保证每一个变更 安全的落盘,这就涉及I/O操作。

  • 对于InnoDB的大部分操作而言,你应该使用设置autocommit=0。从效率的角度看,在你连续插入,更新或删除数据时,这避免了不必要的I/O。从安全的角度讲,在你输入 错误的命令行语句或是在应用中的错误处理程序发生异常时,这允许你执行rollback来进行回滚。

  • autocommit=1适用于为了产生报告,或者分析统计而执行一系列连续查询时,在这种场景下,commit和roll把仓库语句没有I/O成本,而且InnoDB可以自动优化只读负载。

  • 如果你执行了一系列相关修改,可以在结束时使用一个commit来提交。例如,你向多张表插入了数据,然后再执行完所有修改后再进行commit。或者,你执行了很多连续的insert语句,在最后执行一次commit。但是如果你连续执行数百万insert语句的话,恐怕将它们分割成多个事务,比如没1万或10万条记录提交一次,会更好,这样可以避免长事务。

  • 不要忘了:即使一个select语句也会开启一个事务,所以在一个交互式mysql会话中,执行完查询后,记得要提交或者关闭会话。

想深入了解相关信息,请查阅章节15.7.2.2 “自动提交,提交和回滚”