MySQL无法更改ALTER TABLE,而该表正在被主动写入

时间:2018-08-17 20:38:19

标签: java mysql jdbc innodb

在我的应用程序的一种使用情况下,我有两个并发的 MySQL 连接:

  • 主动写入名为T的表中(实际上,不断更新该表中的一行),并且
  • 另一人在同一张表上执行DDL(ALTER TABLE,添加了8个新列,并将一列从varchar(80)扩展到varchar(2000))。 DDL有望最终完成。

UPDATE DML中的列不受DDL的影响。

该表仅包含一行(该行为UPDATE'。

分析

运行涵盖此用例的集成测试时,我观察到的是测试超时(表被如此积极地写入,以致DDL无法完成),但仅针对 MySQL 5.7。通常,在我们的硬件上测试可以在30秒内完成测试(对于 MySQL 5.6和8.0确实如此),但是对于 MySQL 5.7甚至200秒还不够。我尝试了不同的ALGORITHMLOCK值(请参阅13.1.8 ALTER TABLE Syntax),但是没有运气。

当我分析我的应用程序( MySQL 5.7案例)时,我发现99%的CPU时间花费在从套接字读取(即等待 MySQL 响应)上表已被更改),但是数据库实例对我来说却是一个黑匣子-当然,我已启用performance_schema并可以对其执行查询,但是我不知道我要查找哪个确切信息

合成

与此同时,我未能将问题减少到最小的独立单元测试-我观察到的唯一一件事是测试增加了 3x 10x 与其他 MySQL 版本相比, MySQL 5.7所用的时间,但DDL不会永远挂起:

enter image description here

所有 MySQL 版本都是从www.mysql.com下载的 Windows Debian Linux 的常规版本,对{{1 }},或官方的 Docker 图片。

问题:

  1. MySQL 在技术上是否确实可以永远延迟my.cnf DDL的执行?或者我正在观察的只是一个非常繁忙的数据库实例?是否可以
    • 请求ALTER TABLE被中断执行,即e。如果超过了某个超时,数据库将返回错误,或者
    • 强制所有可能甚至在表或其某些行上放置ALTER TABLE锁的其他连接都暂停,以使它们在执行DDL时不干预?
  2. 在处理原始集成测试超时问题时,如何从 MySQL 方面进一步诊断情况?

1 个答案:

答案 0 :(得分:5)

TL; DR-提交交易以解除对ALTER TABLE的阻止。


是的,ALTER TABLE可以长时间阻止。似乎永远。实际上是lock_wait_timeout的值,默认值为31536000秒,即365天。

在MySQL中,像ALTER TABLE这样的DDL语句在表上需要排他的metadata lock。目的是确保您不会同时更改两个并发会话中的TABLE。

DML语句(例如SELECT,INSERT,UPDATE,DELETE)也持有“共享的”元数据锁。共享锁可以由多个会话同时持有,但会阻止独占锁,因为独占锁要求它们是唯一可在表上持有任何类型的锁的锁。

文档状态:

  

这种锁定方法的含义是,一个会话内一个事务正在使用的表在事务结束之前不能在其他会话的DDL语句中使用。

拥有元数据锁的DML语句的目的是使它们可以保留其表的可重复读取视图,而不必担心另一个会话正在执行DROP TABLE或ALTER TABLE来损害其表视图。此锁定是必需的,因为MySQL没有版本化的元数据(they are gradually working toward that)。

这意味着运行简单SELECT且未提交的事务将阻止需要锁定更改的DROP TABLE或ALTER TABLE。

在线DDL的引入有些细微之处。

Online DDL Performance and Concurrency更详细地描述了ALTER TABLE通过获取共享的元数据锁而开始,因此未提交的事务不会阻止它。但是,如果ALTER TABLE更改的性质要求这样做,则下一阶段可以将共享元数据锁升级为独占元数据锁。此时,由于其他事务仍然拥有自己的元数据锁,因此锁定获取被阻止。

在线DDL并不适用于每种类型的ALTER TABLE操作;有些仍然需要排他锁。例如,在更改数据类型时,需要排他锁。有关详细信息,请参见Online DDL Overview