【问题标题】:How do I resolve MySQL INSERT INTO... SELECT causing write lock for SELECTed table?如何解决 MySQL INSERT INTO... SELECT 导致 SELECTed 表的写锁定?
【发布时间】:2013-04-05 07:32:29
【问题描述】:

我有一个单一的、未复制的 MySQL 服务器。

我们遇到了一个问题,即 INSERT INTO ... SELECT 语句导致源表上的写锁定。

原始表在一个数据库中。目标表是另一个数据库中的临时表。

遵循此问题已接受答案的建议:How to improve INSERT INTO ... SELECT locking behavior

我在my.cnf中更改了以下三个配置变量并重启了服务器:

innodb_autoinc_lock_mode=2
binlog_format=row
transaction-isolation=READ-COMMITTED

这似乎使问题变得更糟,尽管在这种情况下相关性可能不是因果关系。

如何防止这种写锁定?

【问题讨论】:

标签: mysql locking


【解决方案1】:

在我看来,您的事务隔离级别在对相同数据进行顺序读取时不允许插入。

了解这可能是件好事。 MySQL 不会在这里无缘无故地阻塞。这只是意味着您的一条语句正在读取的数据在原子操作期间可能不会更改。因此,不授予 INSERT 插入数据的权限,否则会更改您现在插入到临时表中的数据。

您可以查看 this page 从 MySQL 的角度描述有关事务隔离的所有知识。

【讨论】:

  • 那么...我需要实现复制或其他方法来解决这个问题吗?
  • 通过复制解决这个问题似乎有点矫枉过正。如果您了解不同事务隔离级别的作用,则可以降低它以允许非阻塞读取。
  • 似乎设置 innodb_locks_unsafe_for_binlog=1 解决了这个问题。我不知道为什么,但由于@0xCAFEBABE 的建议,我发现了这一点。
【解决方案2】:

this 会帮忙吗?

如果您使用 LOCK TABLES 显式获取表锁,则可以请求 READ LOCAL 锁而不是 READ 锁,以使其他会话在您锁定表时执行并发插入。

要在无法进行并发插入时对表 real_table 执行许多 INSERT 和 SELECT 操作,您可以将行插入临时表 temp_table 并使用临时表中的行定期更新实际表。这可以通过以下代码完成:

mysql> LOCK TABLES real_table WRITE, temp_table WRITE;

mysql> INSERT INTO real_table SELECT * FROM temp_table;

mysql> 从 temp_table 中删除;

mysql> 解锁表;

InnoDB 使用行锁,BDB 使用页锁。这些存储引擎可能会出现死锁,因为它们会在 SQL 语句的处理过程中自动获取锁,而不是在事务开始时。

【讨论】:

  • 不幸的是,这在我们的情况下不起作用,我不认为。除非我误解了这一点,否则这似乎是为了允许修改主表,而不是临时表。
猜你喜欢
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-25
  • 1970-01-01
  • 2012-03-11
  • 1970-01-01
  • 2011-07-12
相关资源
最近更新 更多