这会锁定数据库吗?

l--*_*''' 1 mysql sql

insert into test.qvalues 
  select * from qcvalues.qvalues;
Run Code Online (Sandbox Code Playgroud)

我想知道上面的行是否锁定了数据库 QCVALUES

Mik*_*ike 5

对我来说,文档有点不清楚:

内部锁定方法表明,在某些情况下,可以在另一个会话正在读取 MyISAM 表时插入它:

MyISAM 存储引擎支持并发插入以减少给定表的读取器和写入器之间的争用:如果 MyISAM 表在数据文件中间没有空闲块,则行始终插入到数据文件的末尾。在这种情况下,您可以在没有锁的情况下为 MyISAM 表自由混合并发 INSERT 和 SELECT 语句。也就是说,您可以在其他客户端读取数据的同时将行插入到 MyISAM 表中。空洞可能是由于表中间的行被删除或更新造成的。如果有空洞,并发插入将被禁用,但在所有空洞都被新数据填充后会自动再次启用。

但是,表锁定问题显示了在 SELECT 完成之前表将被锁定的情况(这符合您的情况):

表锁定在以下场景下也是不利的:

  • 会话发出一个需要很长时间才能运行的 SELECT。
  • 然后另一个会话在同一个表上发出 UPDATE。此会话一直等到 SELECT 完成。
  • 另一个会话在同一个表上发出另一个 SELECT 语句。因为 UPDATE 的优先级高于 SELECT,所以这个 SELECT 在等待第一个 SELECT 完成后等待 UPDATE 完成。

InnoDB 表实现了行级锁,所以只有被读取的行会被锁定,而不是整个表。

我没有仅仅依靠文档,而是尝试了一个小测试:

  1. 创建两个具有相同结构的表:table_atable_b
  2. 填充table_a500,000 行。
  3. 使用语句从table_ato复制数据。table_bINSERT INTO ... SELECT
  4. 在复制过程中,使用另一个会话将新行插入到table_a.
  5. 检查是否table_b包含新记录。

当两个表所在的MyISAM,table_b没有包含拷贝后的新记录。当 InnoDB 所在的两个表中,table_b确实包含复制后的新记录。我已经重复了三遍,正如预期的那样,每次结果都是一样的。

因此,简而言之,如果您的表是 MyISAM,它将被锁定。如果是 InnoDB,则不会。当然,这个测试不考虑更新,但我预计结果会相似。