MySQL 和 InnoDB - 在非唯一索引上使用 WHERE 进行更新 - 如何遇到行?

标签 mysql innodb

在非唯一索引列上执行 UPDATE with WHERE 时,表行上下文中的规则如何?

我有一个测试表,其中 col 列作为非唯一索引:

id  |  col
----------
1   |  1
----------
2   |  2
----------
3   |  2
----------
22  |  3


UPDATE tab SET col=1 WHERE col=1;
// OR
UPDATE tab SET col=3 WHERE col=3;
// OR
UPDATE tab SET col=2 WHERE col=2;     
// These updates encounter ONLY rows where col=1, col=3 or col=2

相同的表和相同的更新,但表中多了一条记录,其中 col=2:

id  |  col
----------
1   |  1
----------
2   |  2
----------
3   |  2
----------
4   |  2
----------
22  |  3


UPDATE tab SET col=1 WHERE col=1;
// OR
UPDATE tab SET col=3 WHERE col=3;
// Both updates encounter ONLY rows where col=1 or col=3.

UPDATE tab SET col=2 WHERE col=2;     
// This update encounters ALL the rows in the table even those where col IS NOT 2.
// WHY ?

最佳答案

简而言之,UPDATE 处理过程中遇到的每一行都是独占行锁定的。这意味着 UPDATE 的锁定影响取决于如何处理查询来读取要更新的行。如果您的 UPDATE 查询未使用索引或索引错误,则可能会锁定许多或所有行。 (请注意,锁定行的顺序还取决于所使用的索引。)在您的情况下,由于您的表非常小,并且您正在实质性地更改索引中行的分布,它选择对相关查询使用全表扫描。

您可以通过将大多数 UPDATE 查询转换为 SELECT 并对其使用 EXPLAIN SELECT 来测试它们的性能和行为(在较新的版本中)您甚至可以解释更新)。

简而言之:在测试性能或锁定行为之前,您应该拥有具有实际数据分布的表,而不是具有一些测试行的非常小的表。

关于MySQL 和 InnoDB - 在非唯一索引上使用 WHERE 进行更新 - 如何遇到行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25099025/

相关文章:

mysql - Laravel 在表中与 rowspan 和 <tr> 有很多关系

mysql - MySql如何区分连接之间临时表的不同?

mysql - 在查询中计算适当的总数?

MySQL——删除或索引?

主动/被动拓扑中原始设备上的 Mysql InnoDb

mysql - 指定的 key 太长 : max key lenth is 3072 bytes

mysql - 等效于 MySQL 中的 MSSQL IDENTITY 列

mysql - 在 Perl 中解析表单数据以删除所有非字母数字/标点符号

mysql - 如何从一个表中获取具有特定值或不存在于与第一个表具有 1-1 关系的另一个表中的行?

mysql - 为什么MySQL InnoDB也为更新/删除操作获取间隙锁?