有没有办法跳过"锁定的行"当我们制作"选择更新"在带有InnoDB表的MySQL中?
例如:终端t1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select id from mytable ORDER BY id ASC limit 5 for update;
+-------+
| id |
+-------+
| 1 |
| 15 |
| 30217 |
| 30218 |
| 30643 |
+-------+
5 rows in set (0.00 sec)
mysql>
同时,终端t2:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select id from mytable where id>30643 order by id asc limit 2 for update;
+-------+
| id |
+-------+
| 30939 |
| 31211 |
+-------+
2 rows in set (0.01 sec)
mysql> select id from mytable order by id asc limit 5 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
因此,如果我启动查询强制它选择其他行,那就没问题了。
但是有没有办法跳过锁定的行?
我想这应该是并发过程中的一个冗余问题,但我找不到任何解决方案。
修改: 实际上,我的不同并发过程显然非常简单:
取第一行(不包含特定标志 - 例如:" WHERE myflag_inUse!= 1")。
一旦我得到了我的"选择更新"的结果,我更新标志并提交行。
所以我只想选择尚未锁定的行以及myflag_inUse!= 1 ...
以下链接帮助我理解为什么我会收到超时,但不知道如何避免超时:
MySQL 'select for update' behaviour
mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+-------------------------+
| Variable_name | Value |
+-------------------------+-------------------------+
| innodb_version | 5.5.46 |
| protocol_version | 10 |
| slave_type_conversions | |
| version | 5.5.46-0ubuntu0.14.04.2 |
| version_comment | (Ubuntu) |
| version_compile_machine | x86_64 |
| version_compile_os | debian-linux-gnu |
+-------------------------+-------------------------+
7 rows in set (0.00 sec)
答案 0 :(得分:3)
现在,从8.0.1开始,这似乎存在于MySQL中:
https://mysqlserverteam.com/mysql-8-0-1-using-skip-locked-and-nowait-to-handle-hot-rows/
从MySQL 8.0.1开始,我们将介绍SKIP LOCKED修饰符 它可用于从表中非确定性地读取行 同时跳过锁定的行。这可以用来 我们的预订系统跳过待处理的订单。例如:
但是,我认为该版本不一定是生产就绪。
答案 1 :(得分:2)
不幸的是,到目前为止似乎无法跳过select for update中的锁定行。
如果我们可以使用类似Oracle' FOR UPDATE SKIP LOCKED'这样的话会很棒。
在我的情况下,并行启动的查询都完全相同,并且包含'其中'条款和'组由'数百万行...因为查询需要20到40秒才能运行,这是(我已经知道)问题的很大一部分。
唯一的 - 临时而不是最好的 - 我看到的解决方案是移动一些(即:数百万)行,我不会(直接)按顺序使用减少查询的时间。
所以我仍会有相同的行为,但我会等待更少的时间......
我期待一种不在选择中选择锁定行的方法。
我没有将此标记为答案,因此如果添加(或发现)来自mysql的新子句,我可以在以后接受它......
答案 2 :(得分:0)
对不起,我认为你从错误的角度解决问题。如果您的用户想要列出满足特定选择条件的表中的记录,那么您的查询应该全部返回,或者返回错误消息并且不提供任何结果集。但是查询不应只返回结果的一部分,导致用户相信他拥有所有匹配的记录。
应该通过确保您的应用程序尽可能少地锁定行来解决此问题。
答案 3 :(得分:0)
使用一些合适的PRIMARY KEY
在LIMIT
的大块区域中走过桌子,这样你就不会看到太多"一次排。
通过使用PK,您可以以可预测的方式订购;这实际上消除了死锁。
通过使用LIMIT
,您将不会立刻过度占用。 LIMIT
应体现为PK的范围。这使得两个线程即将相互踩在一起非常清楚。
更多详细信息(间接)在我的blog on big deletes。
中答案 4 :(得分:0)
正如我在this article中所解释的那样,MySQL 8.0引入了对SKIP LOCKED和NO WAIT的支持。
“跳过锁定”对于实现作业队列(也称为批处理队列)很有用,因此您可以跳过并发事务已锁定的锁定。
NO WAIT有助于避免等待并发事务释放我们也希望锁定的锁。没有NO WAIT,我们要么必须等到锁被释放(在当前持有锁的事务在提交或释放时),要么锁获取超时。 NO WAIT的行为类似于值为0
的锁定超时。
有关“跳过锁定”和“无等待”的更多详细信息,请查看this article。