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

时间:2017-05-10 13:34:02

标签: mysql indexing innodb

假设我有一张结构如下的表:

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

name列有一个b树索引。

让我们假设按此顺序对此表进行查询:

  1. INSERT
  2. 选择
  3. INSERT
  4. 现在,我知道在索引表中插入新行时,需要更新索引。这需要时间。但我的问题是

    1. SELECT会等待索引更新,还是只搜索以前版本的表格,或者还有其他内容吗?
    2. 第二次INSERT会发生什么?是否会等待索引从之前的INSERT完全更新?
    3. 谢谢。

        

      更新

      假设插入尚未在SELECT查询发出时更新索引。

3 个答案:

答案 0 :(得分:2)

我认为这里有一些很好的信息: 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查询由于新的Insert而当前正在构建,在构建索引之前不会“看到”新行。

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

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

根据以下评论添加更正和改进

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

更清楚 - 插入不会延迟Select,除非您将数据库配置为在Insert上有表锁,但在插入完成之前,您将看不到任何Select查询中的Insert。

答案 1 :(得分:0)

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

  

在插入行之前,有一种称为插入的间隙锁   意图间隙锁定设置。此锁定表示插入的意图   这样一种方式,多个事务插入到同一个索引中   如果它们没有插入相同的间隙,则不必等待彼此   在差距内的位置。

这是它的总和,但为了深刻理解我建议在引用后阅读整篇文章。

再次,非常感谢您的批准答案。

答案 2 :(得分:-1)

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

INSERT和任何索引更新都是原子的。也就是说,该条目同时被添加到索引中(就任何SQL 而言)是插入的行。

在幕后(在InnoDB中),有一个“更改缓冲区”,它会延迟实际将索引更新写入磁盘。但即使是电源故障也不会违反数据+索引更新的“原子”性质。

事务隔离模式可以让您在包含INSERT的“事务”之前看到(或阻止您查看)记录。但这是一个不同的原子性水平。它与索引无关。