万物之中, 希望至美.

在数据库中为什么尽量不使用长事务?

2018.11.20
  1. 长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这会导致大量的占用存储空间。

在 MySQL 5.5 及以前的版本中,回滚日志跟数据字典一起放在 ibdata 文件里面,即使长事务最终提交,回滚段被清理,文件也不会变小。

  1. 除了对回滚段有影响,长事务还占用锁资源,这也有可能会拖垮整个库。

如何避免长事务对业务的影响

这个问题,我们可以从应用开发端和数据库端分开来看。

从应用端来看:

  1. 确认是否使用了 set autocommit=0。这个确认工作可以在测试环境中开展,把 MySQL 的 general_log 开起来,然后随便跑一个业务逻辑,通过 general_log 的日志来确认。一般框架如果会设置这个值,也就会提供参数来控制行为,你的目标就是把它改成 1。
  2. 确认是否有不必要的只读事务。有些框架会习惯不管什么语句先用 begin/commit 框起来。但有些业务并没有这个需要,但也把好几个 select 语句放到事务中。这种只读事务可以去掉。
  3. 业务连接数据库的时候,根据业务本身的预估,通过 SET MAX_EXECUTION_TIME 命令,来控制每个语句执行的最长时间,避免单个语句意外执行太长时间。

从数据库端来看

  1. 监控 information_schema.innodb_trx 表,设置长事务阀值,超过就报警或者 kill。
  2. Percona 的 pt-kill 这个工具不错,推荐使用。
  3. 在业务功能测试阶段要求输出所有的 general_log,分析日志行为提前发现问题。
  4. 如果使用的是 MySQL 5.6 或者更高的版本,把 innodb_undo_tablespaces 设置成 2 (或者更大的值)。如果真的出现大事务导致回滚段过大,这样设置后清理起来更方便。
comments powered by Disqus