InnoDB 引擎的 MySQL 多值插入的内部工作

Posted

技术标签:

【中文标题】InnoDB 引擎的 MySQL 多值插入的内部工作【英文标题】:Inner working of MySQL multivalue insert for InnoDB engine 【发布时间】:2021-08-25 16:27:28 【问题描述】:

在插入多值插入时,mysql 是否会执行表级锁定,如下所示?这个语句对于 InnoDB 来说是原子的,所以它会保证全有或全无。 MySQL 在底层是如何处理的?

INSERT INTO MyTable ( Column1, Column2 ) VALUES
( Value1, Value2 ), ( Value1, Value2 )

我已阅读https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html,但找不到与此相关的任何特定内容。

【问题讨论】:

它不会锁定表,只会锁定插入的行和插入的索引。 @SoheilRahsaz 感谢您的回复。所以假设我的 column1 是主键,那么如果它执行行级锁定,那么在多线程环境中它是如何工作的? 【参考方案1】:

InnoDB 锁定行而不是表


在这里,我使用带有此示例数据结构的 IntelliJ 控制台创建了一个包含 3 个会话的简单测试用例。

引擎:InnoDB(请注意,我在这里只谈论 InnoDB,我确信不同的引擎是不同的)

Mysql版本:8.0.25

DROP TABLE IF EXISTS `locktest`;
CREATE TABLE locktest
(
    id  INT UNIQUE KEY,
    val INT
);

DROP TABLE IF EXISTS `dataTest`;
CREATE TABLE `dataTest`
(
    id  INT UNIQUE KEY,
    val INT
);


INSERT INTO dataTest
VALUES (1, 1),
       (2, 2),
       (3, 3),
       (4, 4);

现在在会话 1:

START TRANSACTION;

UPDATE dataTest
SET val = 100
WHERE id = 2;

所以现在它正在使用第 2 行并且尚未提交。

然后在第 2 节中:

START TRANSACTION;

INSERT INTO locktest
SELECT id, val from dataTest
WHERE id in (1,2);

正如预期的那样,这不会立即成功,因为它正在等待来自dataTest 的第 2 行的锁定。你可以在这里看到它正在等待:

但它已经成功地将id为1的行插入locktest。我们怎么知道呢?看Session 3

然后在第 3 节:

START TRANSACTION;

INSERT INTO locktest VALUES (10, 200);

INSERT INTO locktest VALUES (1, 200);

这里显示插入 id 为 10 的行发生得很快,但它必须等待下一次插入到locktest,因为在会话 2 中我们插入了一个 id 为 1 的行并且该会话尚未完成。

我们得出的结论是 MySQL 没有完全锁定表 locktest,只锁定 id 为 1 的行(因为 id 是唯一的),它允许插入 id 为 10 的行。

另外,请阅读this 和旁注,注意Gap Locks。

【讨论】:

以上是关于InnoDB 引擎的 MySQL 多值插入的内部工作的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 存储引擎

MYSQL存储引擎InnoDB(二十三):排序索引构建

Mysql Innodb存储引擎 select count 太慢,怎么优化

MySQL InnoDB引擎索引长度受限怎么办

MYSQL优化

Mysql存储引擎