【问题标题】:Does mysql lock table for writes while adding new column with default valuemysql 在添加具有默认值的新列时是否锁定表以进行写入
【发布时间】:2019-05-23 07:17:49
【问题描述】:

如果我在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

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

【问题讨论】:

标签: mysql alter-table


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    NULL 是如何存储的?这就是documentation 所说的:

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

    如果你已经有(比如说)三个可以为空的列,那么提到的位向量中的五个位是未使用的。我们可以假设它们被预设为表示 NULL(这是有道理的)。现在,当您使用 DEAFAULT NULL(这是可空列的默认设置)添加可空列时,无需更改表中的数据 - 只有表元数据。这可以解释为什么 ALTER 操作是“即时的”。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-18
      • 2017-08-31
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 2015-01-08
      • 2022-10-17
      相关资源
      最近更新 更多