【问题标题】:Removing duplicates with unique index删除具有唯一索引的重复项
【发布时间】:2016-04-15 12:22:07
【问题描述】:

我在两个表字段 A、B、C、D 之间插入,相信我已经在 A、B、C、D 上创建了唯一索引以防止重复。但是,我以某种方式简单地对这些进行了正常索引。所以插入了重复项。 2000万条记录表。

如果我将现有索引从普通索引更改为唯一索引,或者只是为 A、B、C、D 添加新的唯一索引,是否会删除重复项,或者由于存在唯一记录而添加失败?我会对其进行测试,但它有 3000 万条记录,我不想弄乱表格或复制它。

【问题讨论】:

  • 你需要使用IGNORE关键字——否则会失败。在小测试台上进行测试。
  • "IGNORE 是标准 SQL 的 MySQL 扩展。它控制 ALTER TABLE 的工作方式,如果新表中的唯一键有重复项或启用严格模式时出现警告..." - @ 987654321@
  • @PaulSpiegel 这很有道理。我尝试复制 Table1,仅结构,并添加唯一索引,然后在原始表和新索引表之间进行插入,但它确实失败了。我这样做是因为在 3000 万条记录上更改或添加唯一索引会花费太长时间。所以现在我在“插入”之后添加了“忽略”,效果很好。

标签: mysql duplicates unique-index


【解决方案1】:

如果您的表中有重复项并且您使用

ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);

查询将失败并出现错误 1062(重复键)。

但是如果你使用IGNORE

-- (only works before MySQL 5.7.4)
ALTER IGNORE TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);

将删除重复项。但是文档没有指定将保留哪一行:

  • IGNORE 是标准 SQL 的 MySQL 扩展。它控制ALTER TABLE 在新表中的唯一键上存在重复项时的工作方式或 如果启用严格模式时出现警告。如果IGNORE 不是 指定,如果重复键错误,副本将中止并回滚 发生。如果指定IGNORE,则仅使用一行 在唯一键上重复。其他冲突的行被删除。 不正确的值被截断为最接近的匹配可接受

    从 MySQL 5.7.4 开始,删除了 ALTER TABLE 的 IGNORE 子句,并且 使用它会产生错误。

(ALTER TABLE Syntax)

如果您的版本是 5.7.4 或更高版本 - 您可以:

  • 将数据复制到临时表中(技术上不需要是临时表)。
  • 截断原始表。
  • 创建唯一索引。
  • 并使用INSERT IGNORE 将数据复制回来(仍然可用)。
CREATE TABLE tmp_data SELECT * FROM mytable;
TRUNCATE TABLE mytable;
ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);
INSERT IGNORE INTO mytable SELECT * from tmp_data;
DROP TABLE tmp_data;

如果您使用 IGNORE 修饰符,则在执行 INSERT 语句被忽略。例如,没有IGNORE,一行 复制表中现有的UNIQUE 索引或PRIMARY KEY 值 导致重复键错误并且语句被中止。和 IGNORE,该行被丢弃,没有错误发生。忽略的错误 而是生成警告。

(INSERT Syntax)

另请参阅:INSERT ... SELECT SyntaxComparison of the IGNORE Keyword and Strict SQL Mode

【讨论】:

  • 这是一个启示。在我可以修改唯一索引以使用与以前不同的列之前,我正在努力摆脱重复。帮了我很多忙 - 谢谢。
  • 看来他们“修复”了这个功能,所以无论你是否使用IGNORE,它仍然会抛出Can't write; duplicate key in table
  • @RVP 对于 5.7.4 及更高版本,您仍然可以使用 INSERT IGNORE ... SELECT ... 复制数据。查看更新。
  • 同样的问题和同样的解决方案。谢谢
【解决方案2】:

您可以使用 ON DUPLICATE KEY UPDATE 代替 IGNORE,这将使您能够控制哪些值应该占上风。

【讨论】:

    【解决方案3】:

    如果您认为会有重复,添加唯一索引将失败。 首先检查有哪些重复项:

    select * from
    (select a,b,c,d,count(*) as n from table_name group by a,b,c,d) x
    where x.n > 1
    

    这可能是对 20M 行的昂贵查询,但会得到所有重复的键,从而阻止您添加主索引。 如果您在子查询中执行 where,则可以将其拆分为更小的块:where a='some_value'

    对于检索到的记录,您必须进行一些更改以使行独一无二。如果这样做了(查询返回 0 行),您应该可以安全地添加主索引。

    【讨论】:

      【解决方案4】:

      回答您的问题 - 在具有重复值的列上添加 UNIQUE 约束将引发错误。

      例如,您可以尝试以下脚本:

      CREATE TABLE `USER` (
        `USER_ID` INT NOT NULL,
        `USERNAME` VARCHAR(45) NOT NULL,
        `NAME` VARCHAR(45) NULL,
        PRIMARY KEY (`USER_ID`));
      
      INSERT INTO USER VALUES(1,'apple', 'woz'),(2,'apple', 'jobs'),
      (3,'google', 'sergey'),(4,'google', 'larry');
      
      ALTER TABLE `USER` 
      ADD UNIQUE INDEX `USERNAME_UNIQUE` (`USERNAME` ASC);
      /*
      Operation failed: There was an error while applying the SQL script to the database.
      ERROR 1062: Duplicate entry 'apple' for key 'USERNAME_UNIQUE'
      */
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-13
        • 1970-01-01
        • 1970-01-01
        • 2016-10-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多