SELECT/INSERT 在 MYSQL InnoDB 中更新索引列时的性能

SELECT/INSERT performance on an indexed column while it's being updated in MYSQL InnoDB

假设我有一个 table 结构如下:

id (int[11]), name(VARCHAR[255])

name 列有一个 b 树索引。

让我们假设这个 table 的查询顺序是这样的:

  1. 插入
  2. SELECT
  3. 插入

现在,我知道在索引 table 中插入新行时需要更新索引。这需要时间。但是我的问题是:

  1. 会 SELECT 等待索引更新还是只搜索以前版本的 table 还是有其他问题?
  2. 第二个 INSERT 会发生什么?它是否会等待索引从之前的 INSERT 完全更新?

谢谢。

UPDATE

假设在发出 SELECT 查询时插入还没有完成更新索引。

我认为这里有一些很好的信息: https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html

和: https://dev.mysql.com/doc/refman/5.7/en/innodb-physical-structure.html

但一般来说,Insert 会锁定该行,但不会阻止 Select(甚至不能阻止新的 Insert)。 Select 依赖于索引的查询,由于新插入而当前正在构建,在构建索引之前不会 "see" 新行。

每个插入操作 = 将数据插入行 + 更改受影响的索引。 您拥有的索引越多,插入过程越长,后续 SELECT 查询找到新行所需的时间就越长。

如果您正在编写代码,那么您可以Select等待插入完成。


根据以下评论进行更正和改进

我不是说语句执行时间比较长,我的意思是如果你在时间A插入一行,需要5秒才能完成操作,那么一个select查询运行在 A+2 秒时看不到该行,在 A+6 秒时 select 查询 运行 会看到该行。

更清楚 - 插入不会延迟 Select,除非您将数据库配置为在插入上有 table 锁,但您不会在任何 [=32= 中看到插入] 查询直到Insert完成。

在 table 中插入一行只会在每个二级索引中插入一个新条目。事实证明,插入数据和在索引中插入新条目实际上是相同的操作——两者都向下钻取 BTree(数据由 PRIMARY KEY 列组织,二级索引由二级键列。

INSERT 连同任何索引更新都是原子的。也就是说,条目被添加到索引的同时( 就您所知 SQL)作为插入的行。

在幕后(在 InnoDB 中),有一个 "Change Buffer" 延迟实际将索引更新写入磁盘。但是即使断电也不违反数据+索引更新的'atomic'性质。

事务隔离模式可以让您看到(或阻止您看到)包含 INSERT 的 "transaction" 之前的记录。但那是不同层次的原子性。并且与索引无关。

我意识到只有我的问题的第一部分得到了明确的回答,我的问题的第二部分找到了明确的答案 - 第二个 INSERT 会发生什么?它会等待索引从之前的 INSERT 完全更新吗? - 在已批准的答案提供的 link 中。

Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.

这是它的总和,但为了深入理解我建议在引用之后阅读整个内容。

再次感谢您认可的回答。