我有一个简单的表,在count列上有一个索引

| Counts   | CREATE TABLE `Counts` (
  `id` bigint NOT NULL,
  `count` int NOT NULL,
  PRIMARY KEY (`id`),
  KEY `count_i` (`count`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |

INSERT INTO Counts (id, count) VALUES (1, 4);
INSERT INTO Counts (id, count) VALUES (2, 4);
INSERT INTO Counts (id, count) VALUES (3, 4);
INSERT INTO Counts (id, count) VALUES (4, 2);
INSERT INTO Counts (id, count) VALUES (5, 2);

我正在try 这样做

SELECT * FROM Counts WHERE count >= 4 ORDER BY count LIMIT 1 FOR UPDATE of Counts SKIP LOCKED`

这样做的 idea 是让MySQL跳过已经锁定的行,并返回给我下一个"非"锁定行.

然而,根据我的测试,尽管我使用的是LIMIT 1,但看起来所有包含count >= 4的行都是锁定的

据我所知,MySQL不会只锁定‘返回’行,还会锁定它扫描到的所有行,以得出这个结果.

EXPLAIN SELECT * FROM Counts WHERE count >= 4 ORDER BY count LIMIT 1

+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | Counts | NULL       | range | count_i       | count_i | 4       | NULL |    3 |   100.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+

这就是为什么这3行被锁定了,但我不明白为什么.

然而,如果不是按计数I排序,而是按主键id排序,我得到1

mysql> EXPLAIN SELECT * FROM Counts WHERE count >= 4 ORDER BY id LIMIT 1;
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | Counts | NULL       | index | count_i       | PRIMARY | 8       | NULL |    1 |    60.00 | Using where |
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

我在count上添加了一个索引并使用order by count,这难道不足以只扫描一行从而锁定它吗?

是我的MySQL docker表现得很奇怪吗?

SELECT @@global.transaction_ISOLATION; == READ-COMMITTED

SELECT @@version == 8.0.33

推荐答案

这就是为什么这3行被锁定了,但我不明白为什么.

然而,如果不是按计数排序,而是按主键ID排序 我得1分

使用InnoDB引擎,它锁定了它必须查看的每一行.

  • 列的唯一索引(主键在MySQL中被认为是唯一的)

    只需锁定一行.

  • A non-unique INDEX on the column
    It must lock all the rows with that value.

  • No index on the column.
    If no index present it has to scan all table, so all rows are locked.

Mysql相关问答推荐

MySQL在带有特定属性值上的对象的数组的杨森对象中搜索

我需要为用户提供MySQL视图和存储的 routine ,但不是基础表

如何计算超过特定数字的所有不同ID组,然后返回这些ID?

S在我的SQL代码中的外键出了什么问题?

MySQL::JSON列的添加使SELECT查询非性能(当需要临时表时)

MySQL全文索引和不区分大小写搜索带来的挑战

如何在 MySQL 中对同一个表的多个列进行 INNER JOIN

如何在 Shopware 6 DAL 中实施 Haversine 公式?

状态为已发货的订单返回产品总数量的SQL(不同的两张表)

任何值的 SQL WHERE 子句?

完全匹配 IN 子句中的所有值

Next-key lock explication - 范围的主键

mysql insert into select join - 通过连接表将值从一列复制到另一表

从 mysql RDS 导出数据以导入 questDb

在 Spring Data jpa 中的 @Query 中无法识别本机查询

使用另一个表中的值更新一个表中的值

MySQL 5.6 DATETIME 不接受毫秒/微秒

获取Count(*)占GROUP BY中所有项目数的百分比

MySQL:唯一字段需要是索引吗?

与 MySql 的连接正在自动中止.如何正确配置Connector/J?