java - MySQL 无法 ALTER TABLE 正在积极写入
问题描述
在我的应用程序的一个用例中,我有两个并发MySQL连接:
- 一个主动写入名为的表
T
(实际上,不断更新此表中的单行),以及 - 另一个对同一个表执行 DDL(
ALTER TABLE
添加 8 个新列并将一列从varchar(80)
to扩展varchar(2000)
)。预计 DDL 最终会完成。
UPDATE
DML 中的列不受DDL 影响。
该表仅包含一行(被UPDATE
'd 的那一行)。
分析
当运行涵盖此用例的集成测试时,我观察到的是测试超时(表被如此积极地写入,因此 DDL 永远不会完成),但仅适用于MySQL 5.7。通常,在我们的硬件上,测试预计会在 30 秒内完成(这确实发生在MySQL 5.6 和 8.0 上),但对于MySQL 5.7,即使 200 秒也是不够的。我尝试了不同ALGORITHM
的LOCK
值(参见13.1.8 ALTER TABLE Syntax),但没有成功。
当我分析我的应用程序(MySQL 5.7 案例)时,我观察到 99% 的 CPU 时间用于从套接字读取(即等待MySQL响应表已被更改),但数据库实例是一种黑色给我的盒子——当然我已经performance_schema
启用并且可以对它运行查询,但我不知道我正在寻找哪些确切的信息。
合成
同时,我未能将问题减少到最小的独立单元测试——我观察到的唯一一件事是MySQL 5.7的测试运行时间与其他MySQL版本相比增加了3到10 倍,但 DDL 没有永远挂着:
所有MySQL版本都是从www.mysql.com下载的Windows或Debian Linux的库存版本,对或官方Docker映像进行了最小的更改。my.cnf
问题:
- MySQL是否真的可以永远延迟
ALTER TABLE
DDL 的执行?或者我观察到的只是一个非常繁忙的数据库实例?是否有可能- 可中断执行的请求
ALTER TABLE
,即如果超过某个超时,数据库将返回错误,或者 - 强制所有其他可能
SHARED
在表或其某些行上加锁的连接暂停,以便在执行 DDL 时它们不会干预?
- 可中断执行的请求
- 在处理原始集成测试超时时,如何从MySQL端进一步诊断情况?
解决方案
TL;DR — 提交您的事务以解锁您的 ALTER TABLE。
是的,ALTER TABLE 可以阻塞很长时间。它可能看起来像永远。实际上就是lock_wait_timeout的值,默认是 31536000 秒,也就是 365 天。
在 MySQL 中,像 ALTER TABLE 这样的 DDL 语句需要对表进行独占元数据锁。目的是确保您不会同时从两个并发会话中更改 TABLE。
SELECT、INSERT、UPDATE、DELETE 等 DML 语句也持有“共享”元数据锁。共享锁可以由多个会话同时持有,但会阻塞排他锁,因为排他锁要求它们是唯一持有表上任何类型锁的锁。
文档指出:
这种锁定方法意味着一个会话中的事务正在使用的表在事务结束之前不能由其他会话在 DDL 语句中使用。
持有元数据锁的 DML 语句的目的是,它们可以保留其表的可重复读取视图,而不必担心另一个会话正在执行 DROP TABLE 或 ALTER TABLE 以损害其表视图。这种锁定是必要的,因为 MySQL 没有版本化元数据(他们正在逐渐朝着那个方向努力)。
这意味着已运行简单 SELECT 且未提交的事务将阻塞需要锁定更改的 DROP TABLE 或 ALTER TABLE。
在线 DDL 的引入存在一些细微差别。
Online DDL Performance and Concurrency更详细地描述了 ALTER TABLE 通过获取共享元数据锁开始,因此未提交的事务不会阻塞它。但如果 ALTER TABLE 更改的性质需要,下一阶段可能会将共享元数据锁升级为独占元数据锁。此时,锁获取被阻塞,因为其他事务仍然持有自己的元数据锁。
在线 DDL 并不适用于所有类型的 ALTER TABLE 操作;有些仍然需要排他锁。例如,正如您所做的那样,更改数据类型需要独占锁。有关详细信息,请参阅在线 DDL 概述。
推荐阅读
- android - 无法检测到后台服务
- sass - 将所有 Clarity 样式规则添加到已建立项目中的最佳方法是什么?
- bash - 如何在bash中自动将两个文件重命名为不同的名称
- javascript - 我无法在 JavaScript 中获取帖子
- python - 使用while循环在python中复制数据行
- javascript - 如何使用javascript函数getTotal在一个html页面中使用多个函数
- vba - 如何使用 VBA 更改 Access 超链接?
- c# - 用 [SerializeField] 注释的变量未显示在检查器中
- swift - 有没有办法让一个按钮在 SwiftUI 中运行多个功能?
- asp.net - 在不使用母版页的 WebForms VB.NET 项目中添加 AntiForgeryToken