正在使用唯一列更新 table

Updating table with unique column

A table 包含以下数据,正在使用 INNODB,对 position/fkUNIQUE 约束,并且不允许 NULL position.

+----+----------+-----+
| id | position | fk  |
+----+----------+-----+
|  1 |        1 | 123 |
|  2 |        2 | 123 |
|  3 |        3 | 123 |
|  4 |        4 | 123 |
|  5 |        5 | 123 |
|  6 |        6 | 123 |
|  7 |        7 | 123 |
|  8 |        8 | 123 |
|  9 |        9 | 123 |
| 10 |       10 | 123 |
+----+----------+-----+

PHP 收到将 table 更新为以下内容的请求。可以提供最方便的请求格式,例如 [2,1,4,3,6,5,8,7,10,9][{"id":1, "position":2}, ... ] 等。

+----+----------+-----+
| id | position | fk  |
+----+----------+-----+
|  1 |        2 | 123 |
|  2 |        1 | 123 |
|  3 |        4 | 123 |
|  4 |        3 | 123 |
|  5 |        6 | 123 |
|  6 |        5 | 123 |
|  7 |        8 | 123 |
|  8 |        7 | 123 |
|  9 |       10 | 123 |
| 10 |        9 | 123 |
+----+----------+-----+

我已经确认 SET unique_checks=0; 不允许暂时禁用唯一检查,并且不希望实际删除唯一索引,更新 table,然后重新应用唯一索引.

如何更新这个table?

如果没有简单的方法,我想到了几个选项,但不喜欢它们:

  1. 允许 NULLposition 中。有没有办法暂时允许 NULL 类似于 SET FOREIGN_KEY_CHECKS=0; 可以禁用外键?
  2. 先删除所有记录,再重新插入。这可能会导致性能问题,因为 table 上有需要重新创建的索引。

我能想到的是,您需要首先将所有位置更改为一些其他值,这些值不在您最终需要设置的新位置值的范围内,但在行中仍然是唯一的。

假设您的头寸列是有符号整数,一种简单的方法是将所有头寸设置为相反(负)值。它们将保持唯一性,但不会出现在新值的集合中。

您可以在一个事务中执行此操作以及您的后续更新,因此其他并发事务将永远不会看到负值。

BEGIN;
UPDATE MyTable SET position = -position;
UPDATE MyTable SET position = 2 WHERE id = 1;
...etc... 
COMMIT;

这是一个技巧。整数的符号位用于显示负数以外的目的。