我正在运行以下MySQL UPDATE语句:

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

我没有使用事务,为什么会得到这个错误?我甚至尝试重新启动我的MySQL服务器,它没有帮助。

该表有406,733行。


当前回答

我们昨天遇到了这个问题,在仔细研究了这里的每一个建议的解决方案,以及其他答案/论坛的其他几个解决方案后,我们最终在意识到实际问题时解决了它。

由于一些糟糕的计划,我们的数据库存储在一个挂载的卷上,该卷也接收我们的常规自动备份。该容量已达到最大容量。

一旦我们清理了一些空间并重新启动,这个错误就被解决了。

注意,我们也手动终止了几个进程:kill <process_id>;所以这仍然是必要的。

总的来说,我们的结论是,令人难以置信的是,我们的日志或警告都没有直接提到磁盘空间不足,但这似乎确实是根本原因。

其他回答

mysql> set innodb_lock_wait_timeout=100;

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+

现在再打开锁。你有100秒的时间向数据库发出一个SHOW ENGINE INNODB STATUS\G,并查看其他哪个事务正在锁定你的事务。

如果您刚刚终止了一个大型查询,那么回滚将需要时间。如果在已终止查询回滚之前发出另一个查询,则可能会得到一个锁定超时错误。这就是我的遭遇。解决办法就是再等一会儿。

细节:

我发出了一个DELETE查询,从大约100万行中删除大约90万行。

我错误地运行了这个(只删除了10%的行): 删除MOD(id,10) = 0的表

而不是这样(删除90%的行): 删除表中MOD(id,10) != 0

我想要删除90%的行,而不是10%。因此,我在MySQL命令行中终止了进程,因为我知道它会回滚到目前为止删除的所有行。

然后我立即运行了正确的命令,并在不久之后得到了一个锁定超时超过错误。我意识到锁实际上可能是被杀死的查询的回滚仍然在后台发生。所以我等了几秒钟,重新运行了查询。

完全符合MarkR的说法。自动提交使每个语句成为一个语句事务。

SHOW ENGINE INNODB STATUS会给你一些死锁原因的线索。还要仔细查看慢速查询日志,看看还有什么正在查询表,并尝试删除正在执行满表罐操作的任何内容。行级锁定工作得很好,但当您试图锁定所有行的时候就不行了!

某些东西阻塞了查询的执行。很可能是另一个查询更新、插入或删除查询中的某个表。你必须找出那是什么:

SHOW PROCESSLIST;

一旦你找到阻塞进程,找到它的id并运行:

KILL {id};

重新运行初始查询。

查看一下您的数据库是否进行了微调,特别是事务隔离。增加innodb_lock_wait_timeout变量不是一个好主意。

检查MySQL中的数据库事务隔离级别:

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

您可以通过更改隔离级别来获得改进。使用类似oracle的READ COMMITTED而不是REPEATABLE READ。REPEATABLE READ是InnoDB的默认值。

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

此外,仅在必要时尝试使用SELECT FOR UPDATE。