MySQL InnoDB“;选择以进行更新";-跳转锁定等价物
在使用InnoDB表的MySQL中进行“选择更新”时,有没有跳过“锁定行”的方法? 例如:终端t1MySQL InnoDB“;选择以进行更新";-跳转锁定等价物,mysql,sql,multithreading,concurrency,innodb,Mysql,Sql,Multithreading,Concurrency,Innodb,在使用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 | | 30
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>
因此,如果我启动一个查询,强制它选择其他行,就可以了
但是有没有办法跳过锁定的行呢
我想这应该是并发进程中的一个冗余问题,但我没有找到任何解决方案
编辑: 实际上,我的不同并发进程正在做一些显然非常简单的事情:
下面的链接帮助我理解超时的原因,而不是如何避免超时:
对不起,但我认为你从错误的角度看待这个问题。如果用户希望列出满足某些选择条件的表中的记录,那么查询应该返回所有记录,或者返回错误消息,并且不提供任何结果集。但是查询不应该只返回结果的一个子集,从而让用户相信他拥有所有匹配的记录
应该通过确保应用程序锁定尽可能少的行、尽可能少的时间来解决此问题。不幸的是,目前为止,似乎无法跳过select for update中锁定的行。 如果我们可以使用类似Oracle的“更新跳过锁定”功能,那就太好了 在我的例子中,并行启动的查询都完全相同,并且在数百万行上包含一个“where”子句和一个“groupby”……因为查询需要20到40秒才能运行,这是(正如我已经知道的)问题的很大一部分 我看到的唯一临时而不是最佳的解决方案是移动一些(即:数百万)我不会(直接)使用的行,以减少查询所需的时间 所以我仍然会有同样的行为,但我会等更少的时间 我希望有一种方法不选择select中锁定的行。
我不会将此标记为答案,因此如果添加(或发现)mysql中的新子句,我可以稍后接受它…使用一些合适的
限制,以主键的块遍历表,这样您就不会一次查看“太多”行
通过使用PK,您可以以可预测的方式订购物品;这实际上消除了死锁
通过使用限制
,您将避免一次占用过多的空间。限制
应体现为PK上的一个范围。如果两个线程将要相互踩在一起,这就非常清楚了
更多详细信息(间接)见my.从8.0.1开始,MySQL中似乎存在以下内容:
从MySQL 8.0.1开始,我们将引入SKIP-LOCKED修饰符
可用于非确定性地从表中读取行
跳过锁定的行时。这可以由
我们的预订系统可以跳过待定的订单。例如:
但是,我认为该版本不一定能生产。MySQL 8.0引入了对跳过锁定
和无等待
的支持
SKIP LOCKED
对于实现作业队列(也称为批处理队列)非常有用,这样您就可以跳过已被并发事务锁定的锁
NO WAIT
有助于避免等待并发事务释放我们也感兴趣的锁
如果没有NO WAIT
,我们必须等待锁被释放(当前持有锁的事务在提交或释放时),或者锁获取超时<代码>无等待
用作锁定超时,值为0
有关和的更多详细信息,请参见NO WAIT
,谢谢您的回答。但是,在我的例子中,我有几个进程在//中运行。他们更新mytable上的数据。我只想更新一些数据,以便能够在//中启动几个线程,并加快全局更新。当然,我在real where子句中有额外的条件,但我在这里只展示了一个简单的例子。很抱歉,我不可能对我不熟悉的设计发表评论。您需要查看您的流程,并评估它们锁定记录的方式是否合适,甚至这些流程的设计方式是否合适。确定。我的不同并发进程所做的事情显然非常简单:取第一行(不包含特定标志)。一旦得到“selectforupdate”的结果,我就会更新标志并提交行。因此,我只想选择尚未锁定的行…@Bast“真正简单”的操作实际上是一个复杂的操作-您正在尝试模拟签入/签出操作。你不能用你发现的更新锁来模拟这一点。您不仅会遇到超时,应用程序还必须在整个操作期间保持连接打开。如果您试图在不同的服务器上执行长时间运行的操作,这是一个坏主意machine@Bast然后使用标志字段而不是锁定,或者使用允许您查看未限制更改的隔离模式,或者在长期事务之外更新标志字段。只是不要使用SELECT FOR update
。长时间使用更新锁是个坏主意,而且只有在使用游标时才有用(这也不是个好主意)。您不能使用它来模拟签入/签出mechanism@PanagiotisKanavos,我不想要
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)