SELECT ... ORDER BY xxx LIMIT 1 FOR UPDATE 将锁定多少行?

2024-02-05

我有一个具有以下结构的查询:

SELECT ..... WHERE status = 'QUEUED' ORDER BY position ASC LIMIT 1 FOR UPDATE;

这是 InnoDB 表上的单表 SELECT 语句。场地position(INT NOT NULL) 上有一个索引。状态是 ENUM 并且也被索引。

SELECT ... FOR UPDATE手册页说,它锁定它读取的所有行。我是否理解正确,在这种情况下只有一行会被锁定?或者更确切地说,它会锁定整个表?

是否可以确定哪些行将被锁定EXPLAIN询问?如果是的话 - 怎么办?对空表的查询解释显示以下内容:

1;'SIMPLE';'job';'index';<null>;'index_position';[34,...];<null>;1;'Using where'

这是一个很好的问题。 InnoDB是行级锁定引擎,但它必须设置额外的锁来确保二进制日志(用于复制;时间点恢复)的安全。要开始解释它,请考虑以下(简单的)示例:

session1> START TRANSACTION;
session1> DELETE FROM users WHERE is_deleted = 1; # 1 row matches (user_id 10), deleted.
session2> START TRANSACTION;
session2> UPDATE users SET is_deleted = 1 WHERE user_id = 5; # 1 row matches.
session2> COMMIT;
session1> COMMIT;

因为语句只有在提交后才会写入二进制日志,所以在从属会话#2 上将首先应用,并会产生不同的结果,导致数据损坏.

InnoDB 所做的就是设置额外的锁。如果is_deleted被索引,那么在 session1 提交之前没有其他人能够修改或插入范围记录的数量,其中is_deleted=1。如果没有索引is_deleted,那么InnoDB需要锁定整个表中的每一行以确保重放的顺序相同。你可以将其视为锁定间隙, 这是与直接掌握行级锁定不同的概念.

在你的情况下ORDER BY position ASC,InnoDB需要确保在最低键值和“特殊”最低可能值之间不能修改任何新行。如果你做了类似的事情ORDER BY position DESC..好吧,那么没有人可以插入这个范围。

所以解决方案来了:

  • 基于语句的二进制日志记录很糟糕。我真的很期待我们都转向的未来基于行的二进制日志记录 http://dev.mysql.com/doc/refman/5.1/en/replication-formats.html(从 MySQL 5.1 开始可用,但默认情况下不启用)。

  • 对于基于行的复制,如果将隔离级别更改为已提交读,则只需锁定匹配的一行。

  • 如果你想成为受虐狂,你也可以开启innodb_locks_unsafe_for_binlog http://dev.mysql.com/doc/refman/5.0/en/innodb-parameters.html#sysvar_innodb_locks_unsafe_for_binlog具有基于语句的复制。


4 月 22 日更新:复制+粘贴我的测试用例的改进版本(它不是在“间隙”中搜索):

session1> CREATE TABLE test (id int not null primary key auto_increment, data1 int, data2 int, INDEX(data1)) engine=innodb;
Query OK, 0 rows affected (0.00 sec)

session1> INSERT INTO test VALUES (NULL, 1, 2), (NULL, 2, 1), (5, 2, 2), (6, 3, 3), (3, 3, 4), (4, 4, 3);
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

session1> start transaction;
Query OK, 0 rows affected (0.00 sec)

session1> SELECT id FROM test ORDER BY data1 LIMIT 1 FOR UPDATE;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

session2> INSERT INTO test values (NULL, 0, 99); # blocks - 0 is in the gap between the lowest value found (1) and the "special" lowest value.

# At the same time, from information_schema:

localhost information_schema> select * from innodb_locks\G
*************************** 1. row ***************************
    lock_id: 151A1C:1735:4:2
lock_trx_id: 151A1C
  lock_mode: X,GAP
  lock_type: RECORD
 lock_table: `so5694658`.`test`
 lock_index: `data1`
 lock_space: 1735
  lock_page: 4
   lock_rec: 2
  lock_data: 1, 1
*************************** 2. row ***************************
    lock_id: 151A1A:1735:4:2
lock_trx_id: 151A1A
  lock_mode: X
  lock_type: RECORD
 lock_table: `so5694658`.`test`
 lock_index: `data1`
 lock_space: 1735
  lock_page: 4
   lock_rec: 2
  lock_data: 1, 1
2 rows in set (0.00 sec)

# Another example:
select * from test where id < 1 for update; # blocks
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SELECT ... ORDER BY xxx LIMIT 1 FOR UPDATE 将锁定多少行? 的相关文章

随机推荐

  • JLabel setText 不更新文本

    我正在尝试使用以下方法更新 JLabelsetText 方法 但我无法重绘 JLabel 我必须使用repaint 方法来做到这一点 这是代码的一部分 我没有收到任何错误 但它没有更新 JLabel public void actionPe
  • 将 infoWindow 放置在远离标记的静态位置(Google 地图)

    我想要实现的 到目前为止找不到任何东西 是 infoWindow 没有附加到标记 我想将其放置在视口中的静态位置 并根据单击的标记交换内容 问 如何将谷歌地图标记信息窗口放置 而不仅仅是偏移 到固定位置 回答我自己的问题 如果有人需要这个
  • 如何禁用 #line 指令写入 T4 生成输出文件

    我在生成 T4 代码时遇到了一个小问题 我已将 T4 模板分解为单独的文件并将它们放置在不同的目录中 我已经这样做了 因此我的代码生成的部分内容可以在多个项目中重复使用 例如模型生成 存储库生成和服务生成都包含核心 EntityGenera
  • 双控制台输出?

    突然 当我在本地运行我的应用程序时 我得到了双控制台输出 有谁知道这可能是什么原因造成的 运行 Thin 和 Unicorn 时都存在该问题 gt Booting Thin gt Rails 4 0 0 application starti
  • 在 odoo 中安装 woocommerce 连接器

    我想连接 woocommerce 和 odoo 我在 Odoo 中安装 woocommmerce 连接器时遇到问题 我从那里得到了 woocommerce 连接器https github com OCA connector woocomme
  • 没有规则可以创建“opencv.exe”所需的目标“C:/opencv/build/lib/libopencv_world300d.dll.a”。停止

    所以我试图构建一个简单的 opencv 代码 但我不断收到此错误 而且我似乎在互联网上找不到任何解决方案 操作系统 Windows 8 1 编译器 GNU GCC 601 IDE CLion CMake 3 0 和 mingw64 这是我从
  • spring-mvc中将json解析为java对象

    我熟悉如何从我的返回 json Controller方法使用 ResponseBody注解 现在我正在尝试将一些 json 参数读入我的控制器 但到目前为止还没有运气 这是我的控制器的签名 RequestMapping value ajax
  • findOneAndUpdate 覆盖作为 doc 传递的 2 级以上深度对象中的属性

    假设我有这个架构 var UserSchema new Schema name firstName String lastName String 我创建这个用户 User create name firstName Bob lastName
  • 用户点击时使用ajax加载processing.js sketch

    我正在尝试通过单击 ajax 加载processing js 草图 但它不起作用 如果我立即加载草图 它会起作用 但不会在用户交互时加载 这是我的代码 clicker click function var canvasRef
  • 避免 Google Apps 脚本中出现 formatDate 错误

    我有一个函数可以存储在数组中并循环文档中的数据 在这个里面 有一些单元格的日期格式为 dd mm yyyy 但是当我通过电子邮件发送它时 看起来像2014 年 1 月 1 日星期三 00 00 00 GMT 0300 ART 我在这个函数内
  • IA-64 上出现段错误,但 IA-32 上没有

    我无法访问我的原始账户 https stackoverflow com users 211631 whacko cracko 如果可能的话 请版主合并帐户 这是我的问题 以下 C 程序在 IA 64 上出现段错误 但在 IA 32 上运行良
  • 使用 AngularJS 日期过滤器和 UTC 日期

    我有一个以毫秒为单位的 UTC 日期 我将其传递给 Angular 的日期过滤器以进行人工格式化 someDate date d MMMM yyyy 太棒了 除了someDate采用 UTC 时间 并且日期过滤器认为它是当地时间 我如何告诉
  • String(value) 与 value.toString() 有什么区别

    Javascript 在类型和类型转换方面有很多 技巧 所以我想知道这两种方法是否相同 或者是否存在某些特殊情况使它们不同 它们并不完全相同 实际上 作为函数调用的 String 构造函数 http bclary com 2004 11 0
  • Android:打开指定多个收件人的短信活动[重复]

    这个问题在这里已经有答案了 我正在尝试通过启动意图来启动手机短信提供商 我下面使用的代码是我用来启动意图的代码 Intent sendIntent new Intent Intent ACTION VIEW StringBuilder ur
  • 我应该在 git 别名脚本中使用 `sh -c \"...\"` 或 `"!f() {... ; }; f" 吗?

    我已经开始尝试编写带参数的 git 别名了 我见过一些人运行 shell 脚本 alias shAlias sh c 和其他运行函数 alias fAlias f f 看起来 一旦我加快了 Bash 的速度 这还不是我现在的状态 我想要做的
  • 在清单中声明 Google api 密钥(对于 youtube API)

    使用地图 API 我可以在清单中声明我的密钥
  • 部署的 Azure Function (v2) 未运行

    我有一个 Azure Function v2 可以在本地运行 部署到 Azure 后 一切似乎都正常 包含二进制文件的 bin 文件夹和包含 function json 的函数名称文件夹 但是 当我检查它们是否运行 查看日志 时 它们不在监
  • JavaScript 中的 DOM 解析

    一些背景 我正在使用 JavaScript 开发一个基于 Web 的移动应用程序 HTML 渲染基于 Safari 跨域策略已禁用 因此我可以使用 XmlHttpRequests 调用其他域 这个想法是解析外部 HTML 并获取特定元素的文
  • 使用 Haskell 输入数据

    背景故事 为了更好地理解 Haskell 和函数式编程 我给自己布置了一些作业 我的第一个任务是编写一个程序 可以查看数据集 一组数字 博客中的单词等 搜索模式或重复 对它们进行分组并报告它们 听起来很容易 Question 我希望程序首先
  • SELECT ... ORDER BY xxx LIMIT 1 FOR UPDATE 将锁定多少行?

    我有一个具有以下结构的查询 SELECT WHERE status QUEUED ORDER BY position ASC LIMIT 1 FOR UPDATE 这是 InnoDB 表上的单表 SELECT 语句 场地position I