MySQL InnoDB“;选择以进行更新";-跳转锁定等价物

MySQL 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

在使用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”)

  • 一旦得到“selectforupdate”的结果,我就会更新标志并提交行

  • 因此,我只想选择尚未锁定的行以及myflag_使用的位置=1


    下面的链接帮助我理解超时的原因,而不是如何避免超时:



    对不起,但我认为你从错误的角度看待这个问题。如果用户希望列出满足某些选择条件的表中的记录,那么查询应该返回所有记录,或者返回错误消息,并且不提供任何结果集。但是查询不应该只返回结果的一个子集,从而让用户相信他拥有所有匹配的记录


    应该通过确保应用程序锁定尽可能少的行、尽可能少的时间来解决此问题。

    不幸的是,目前为止,似乎无法跳过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)