【问题标题】:How to auto increment on unique value如何自动增加唯一值
【发布时间】:2015-10-17 00:10:48
【问题描述】:

假设我在 mysql 工作台和 Innodb 引擎中有这张表,两列都作为主键:

+--------+---------+
| grp    | name    |
+--------+---------+
| fish   | lax     |
| mammal | dog     |
| mammal | bat     |
| mammal | whale   |
| bird   | bat     |
| bird   | ostrich |
+--------+---------+

如何添加一个列,使用 grp 列的行为如下:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  2 | dog     |
| mammal |  2 | cat     |
| mammal |  2 | whale   |
| bird   |  3 | penguin |
| bird   |  3 | ostrich |
+--------+----+---------+

请注意,我要更改的实际表要大得多。另请注意,这不是使用 MyISAM 自动递增的功能,也不是此处要求的功能(但答案可能会有所帮助):How to auto increment on different foreign keys?

【问题讨论】:

  • 也许查看触发器,查询它是否在其中,从id 列中获取MAX 并递增一
  • 好吧,正确的方法(在广泛接受的数据库规范化概念中)是在该表中没有这样的列 - 新 ID 属于 grp 表,它可以从作为外键引用(而不是重复组名)。
  • @IMSop ,这正是我想要在现有数据库中做的事情。这将是第一步。然后我会将 (grp,id) 对插入到一个新表中(或更新一个现有的空表),这是您提到的 grp 表。之后我会从第一个表中删除 grp 列。另一种方法是首先使用自动增量 id 和该表的 grp 值创建 grp 表。假设第一个表是动物,我添加了空的 id 列。然后我必须这样做: UPDATE Animals as A, Grp as G SET A.id=G.id WHERE A.grp=G.grp;这种方式的复杂度是O(sizeA * sizeG),太大了
  • @IMSop 我的表大小是 200k 和 100k。我在一夜之间离开了那个更新,它完成了,但必须有一个更快的解决方案。因此,找到一种方法可以在表 A 中创建 id,然后只插入对应该具有 O(sizeA + sizeG) 的复杂度,这很好。
  • 我不确定您是如何计算这些复杂度值的。无论哪种方式,您都必须更新表中的每一行一次,并且您必须查找该行所属的组才能这样做。唯一可以改变的是查找的方式。如果组数较少,您甚至可以进行多次更新,例如SET grpid=4 WHERE grp='fish'"

标签: mysql innodb mysql-workbench auto-increment


【解决方案1】:
CREATE TABLE Groups (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    grp VARCHAR...
    PRIMARY KEY(id),
    UNIQUE(grp)
        ) ENGINE=InnoDB
    SELECT DISTINCT grp FROM YourTable;

这应该会给你grpid 之间的映射。

此时,您不应生成具有 3 列 (grp+id+name) 的表,而是使用上面的 Groups 作为“规范化”,您似乎正在这样做。然后做

CREATE TABLE New LIKE YourTable;
ALTER TABLE New
    ADD  COLUMN id INT UNSIGNED NOT NULL,
    DROP COLUMN grp;
# Note: if you have an index on grp, something else may need to be done.
INSERT INTO New
    SELECT g.id, y.name
        FROM Groups g
        JOIN YourTable y  ON y.grp = g.grp;
# At this point, verify that `New` has what you want.  Then switch over:
RENAME TABLE YourTable TO Old, New TO YourTable;
DROP TABLE Old;

编辑我选择创建一个新表而不是更新现有表——因为它(我认为)会快得多。使用UPDATE,所有行都需要被锁定。使用INSERT..SELECT,它们被简单地创建了。

【讨论】:

  • 谢谢!然而,这并不能回答我的问题。我已经这样做了,并进行了更新。加入/更新的条件过于复杂。它为 g 的每一行扫描 y,导致 O(sizey*sizeg) 复杂度。这就是为什么我问如何生成该表。如果有一种不太复杂的方法,那就是一个简单的操作就可以得到相同的结果。我做了整晚的更新。
  • grp 有一个主索引,因为它是主键的一部分。仍然对我来说很好。我是在更新完成后这样做的。如果有索引,删除列是否有问题?此外,使用临时表是否可以提高性能,还是只是为了安全?使用不带别名的更新时出错。关于锁的东西。也许使用别名在内部创建了临时表,这解决了这个问题。使用 join 代替更新是否有性能提升?我知道建议使用 join over update ,这是为什么呢?我知道加入是无论如何都会发生的事情,对吧?
  • (我编辑了我的回复。)JOIN 仅在您说 JOIN(或使用“comma-JOIN”:FROM a, b)时才会发生。
  • 内部没有使用加入更新吗?事实上,我曾在某处看到它是一种已弃用的 join 语法,不应使用它来代替它。每行是否通过更新分别锁定和解锁?它不只是将所有这些都锁定一次,以确保它们的可用性,对吗?如果列有索引,删除列是否有问题?
  • 如果没有 2 个表,就不能有 JOIN。 InnoDB 将锁定它需要的行,并保持锁定直到语句完成。 (实际上是“一次全部”。)我不知道如果您删除一列而没有首先(或在同一个 ALTER 中)删除包含它的任何索引会发生什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-09
相关资源
最近更新 更多