mysql在添加具有默认值的新列时是否锁定表写入

时间:2019-05-23 07:17:49

标签: mysql alter-table

如果我在sql下执行,mysql将锁定完整表(在以下操作完成之前无法进行写操作)吗? 我认为是的,因为它必须修改所有行并添加默认值。但是,此操作在具有100万行的表上仅花费了4秒。

ALTER TABLE `user` ADD COLUMN `col1` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1;

但是,当我尝试将操作分为2个单独的查询(基于我的不完全理解来尝试减少表锁定时间)时,第二个查询运行了100多秒钟

ALTER TABLE `user` ADD COLUMN `col1` TINYINT(1) UNSIGNED; // happens instantly
UPDATE user set col1 = true ; // takes > 100 seconds

所以我想知道为什么最终结果相同时执行时间会有如此大的差异。

2 个答案:

答案 0 :(得分:0)

我不能肯定地说,但这是我的猜测(对于InnoDB引擎和DYNAMIC / COMPACT行格式):

如何存储NULL? documentation这样说:

  

记录头的可变长度部分包含一个位向量   用于指示NULL列。如果索引中的列数   可以是NULLN,则位向量占据   CEILING(N/8)个字节。 (例如,如果有   从9到16列(可以是NULL的任何位置),位向量使用   两个字节。)NULL列不占用除   此向量中的位。 [...]

如果您已经有(例如)三个可为空的列,则上述位向量中的五个位均未使用。我们可以假设它们已预先设置为代表NULL(这很有意义)。现在,当您使用DEAFAULT NULL添加可为空的列(这是可为空的列的默认设置)时,表中的任何数据都不必更改,只需更改表元数据即可。这可以解释为什么ALTER操作是“即时的”。

第二部分(UPDATE语句)不仅会更改表中每一行的内容,还会更改其大小。这意味着引擎必须为每一行找到一个新的空间。如果您曾经看过碎片整理过程,则可能会知道,仅重写整个数据通常会更快。

答案 1 :(得分:0)

https://mysqlserverteam.com/mysql-8-0-innodb-now-supports-instant-add-column/上找到了答案 使用INSTANT算法,innoDB只需将新列以及默认值添加到表元数据中。不修改单个行,从而节省了我提到的第一个查询的时间。 所有读取操作都使用表元数据中的默认值,任何写入操作都会重构该行,并在该行本身中添加新添加的列。 将单个ALTER操作拆分为2的过程很慢,因为后者正在修改每一行。