### 8.5.2 优化 InnoDB 事务管理

优化`InnoDB`事务处理，在事务特性的性能开销和服务器的工作负载之间找到理想的平衡点。例如，如果一个应用程序每秒提交数千次，它可能会遇到性能问题，如果它仅每 2-3 小时提交一次，则可能会遇到不同的性能问题。

-   默认 MySQL 设置`自动提交=1`可以对繁忙的数据库服务器施加性能限制。在可行的情况下，通过发出`设置自动提交=0`或一个`开始交易`声明，然后是`犯罪`进行所有更改后的声明。

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

-   或者，对于仅包含单个[`选择`](select.html)声明，开启`自动提交`帮助`InnoDB`识别只读事务并优化它们。看[第 8.5.3 节，“优化 InnoDB 只读事务”](innodb-performance-ro-txn.html)为要求。

-   避免在插入、更新或删除大量行后执行回滚。如果一个大事务正在降低服务器性能，回滚它会使问题变得更糟，可能需要数倍于原始数据更改操作的时间来执行。杀死数据库进程没有帮助，因为回滚在服务器启动时再次开始。

    为了尽量减少发生此问题的机会：

    -   增加尺寸[缓冲池](glossary.html#glos_buffer_pool)这样所有的数据变化变化都可以被缓存而不是立即写入磁盘。

    -   放[`innodb_change_buffering=全部`](innodb-parameters.html#sysvar_innodb_change_buffering)这样除了插入之外，更新和删除操作也会被缓冲。

    -   考虑发行`犯罪`在大数据更改操作期间定期执行语句，可能会将单个删除或更新分解为对较少行数进行操作的多个语句。

        要在回滚发生后摆脱失控回滚，请增加缓冲池以使回滚成为 CPU 密集型并快速运行，或者终止服务器并重新启动[`innodb_force_recovery=3`](innodb-parameters.html#sysvar_innodb_force_recovery)，如中所述[第 15.18.2 节，“InnoDB 恢复”](innodb-recovery.html).

        此问题预计在默认设置下很少发生[`innodb_change_buffering=全部`](innodb-parameters.html#sysvar_innodb_change_buffering)，它允许将更新和删除操作缓存在内存中，从而使它们首先执行得更快，并且在需要时也可以更快地回滚。确保在处理具有许多插入、更新或删除的长时间运行事务的服务器上使用此参数设置。

-   如果发生意外退出，如果您能够承受丢失一些最新提交的事务，您可以设置[`innodb_flush_log_at_trx_commit`](innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit)参数为 0。`InnoDB`无论如何都会尝试每秒刷新一次日志，尽管不能保证刷新。

-   当行被修改或删除时，行和关联的[撤消日志](glossary.html#glos_undo_log)不会立即物理删除，甚至不会在事务提交后立即删除。保留旧数据，直到更早或同时启动的事务完成，以便这些事务可以访问已修改或已删除行的先前状态。因此，长时间运行的事务可以防止`InnoDB`从清除由不同事务更改的数据。

-   当在一个长时间运行的事务中修改或删除行时，其他事务使用[`阅读已提交`](innodb-transaction-isolation-levels.html#isolevel_read-committed)和[`可重复阅读`](innodb-transaction-isolation-levels.html#isolevel_repeatable-read)如果隔离级别读取相同的行，则必须做更多的工作来重建旧数据。

-   当一个长时间运行的事务修改一个表时，从其他事务对该表的查询不会使用[覆盖指数](glossary.html#glos_covering_index)技术。通常可以从二级索引中检索所有结果列的查询，而不是从表数据中查找适当的值。

    如果发现二级索引页面有`PAGE_MAX_TRX_ID`那太新了，或者如果二级索引中的记录被删除标记，`InnoDB`可能需要使用聚集索引查找记录。
