【问题标题】:Altering MySQL (Percona 5.7) table fails because of duplicate entry errors由于重复条目错误,更改 MySQL (Percona 5.7) 表失败
【发布时间】:2018-12-21 10:06:58
【问题描述】:

我们已将 MySQL (Percona) 从 5.6 更新到 5.7,我们被告知需要更改/修复某些表,因为“日期时间”字段现在不同了。尽管在两个字段 device_id 和 ts 上都有主键,但更改表失败并出现重复条目​​错误,并且所有数据似乎都正常(没有重复)。据我所知,主键也必须是唯一的。

我们尝试通过 WHERE 部分中的 'device_id' 和 'ts' 条件选择重复条目,但它只找到了 1 个记录实例。当我们尝试仅通过 ts 字段进行选择时,它会找到同一记录的 2 个实例。这怎么可能?那些重复是什么?密钥是否损坏?除了在那里创建一个新表并使用 INSERT IGNORE 管道所有数据之外,还有其他方法吗?

编辑:错误如下:

ERROR 1062 (23000): Duplicate entry '486-2014-10-26 02:39:33' for key 'PRIMARY'

编辑2:表结构如下(device_id、ts和32个传感器):

CREATE TABLE IF NOT EXISTS `sensor_log` (
    `device_id` int(11) NOT NULL,
    `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `D1` smallint(6) DEFAULT NULL,
    `D2` smallint(6) DEFAULT NULL,
    ...
    `D30` smallint(6) DEFAULT NULL,
    `D31` smallint(6) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
/*!50100 PARTITION BY RANGE ( UNIX_TIMESTAMP(ts))
(PARTITION p_sl_2013 VALUES LESS THAN (1388530800) ENGINE = InnoDB,
    PARTITION p_sl_2014 VALUES LESS THAN (1420066800) ENGINE = InnoDB,
    PARTITION p_sl_2015 VALUES LESS THAN (1451602800) ENGINE = InnoDB,
    PARTITION p_sl_2016 VALUES LESS THAN (1483225200) ENGINE = InnoDB,
    PARTITION p_sl_2017_q1 VALUES LESS THAN (1490997600) ENGINE = InnoDB,
    PARTITION p_sl_2017_q2 VALUES LESS THAN (1498860000) ENGINE = InnoDB,
    PARTITION p_sl_2017_q3 VALUES LESS THAN (1506808800) ENGINE = InnoDB,
    PARTITION p_sl_2017_q4 VALUES LESS THAN (1514761200) ENGINE = InnoDB,
    PARTITION p_sl_2018_q1 VALUES LESS THAN (1522533600) ENGINE = InnoDB,
    PARTITION p_sl_2018_q2 VALUES LESS THAN (1530396000) ENGINE = InnoDB,
    PARTITION p_sl_2018_q3 VALUES LESS THAN (1538344800) ENGINE = InnoDB,
    PARTITION p_sl_2018_q4 VALUES LESS THAN (1546297200) ENGINE = InnoDB,
    PARTITION p_sl_2019_q1 VALUES LESS THAN (1551394800) ENGINE = InnoDB,
    PARTITION p_sl_2019_q2 VALUES LESS THAN (1556661600) ENGINE = InnoDB,
    PARTITION p_sl_2019_q3 VALUES LESS THAN (1561932000) ENGINE = InnoDB,
    PARTITION p_sl_2019_q4 VALUES LESS THAN (1567288800) ENGINE = InnoDB,
    PARTITION p_sl_2019_q5 VALUES LESS THAN (1572562800) ENGINE = InnoDB,
    PARTITION p_sl_2019_q6 VALUES LESS THAN (1577833200) ENGINE = InnoDB,
    PARTITION p_sl_X VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */;

--
-- Indexes for table `sensor_log`
--
ALTER TABLE `sensor_log`
ADD PRIMARY KEY (`device_id`,`ts`);

【问题讨论】:

  • 请始终包含完整的错误消息以及表定义等其他有用信息。您可以节省大量的写作时间,这样可以避免混淆和猜测。
  • 我完全忘记了也可能添加错误。我现在已经添加了。我们还尝试使用 FORCE 更改 TABLE,但出现相同的错误。

标签: mysql duplicates alter-table percona mysql-5.7


【解决方案1】:

当错误看起来像这样时:

ERROR 1022 (23000): Can't write; duplicate key in table '#sql-6b04_a0'

那么您可能会尝试使用相同名称创建两次外键。或类似的东西。检查你的外键。

如果您想强制将表格更新为新格式,则无需对表格进行任何更改。做吧

ALTER TABLE foo FORCE;

编辑:

您的表格中有重复的条目。您的主键跨越两列。查找那些重复的

SELECT device_id, ts, COUNT(*)
FROM your_table
GROUP BY device_id, ts
HAVING COUNT(*) > 1

然后你必须清理你的表,确保每个 device_id 和 ts 组合只有一个条目。

【讨论】:

  • 我在最初的帖子中提到,在 WHERE 部分的两列中选择数据时,重复项不可见。仅当您仅选择一列时才会看到重复项,例如 ts。为确保情况确实如此,我们已经执行了您在上面编写的 SELECT 查询并返回:空集(7 小时 53 分 38.30 秒)。
  • 当您的查询运行将近 8 小时时,您几乎可以肯定没有选择构成主键的列。或者您的数据库在 USB 2.0 记忆棒或其他东西上运行。您的错误消息会准确地告诉您它是哪一行。 486-2014-10-26 02:39:33 表示 `486 是主键第一部分的值,其余部分是主键中的时间戳列。您是否选择了正确的列?我不知道,因为你仍然没有像我一开始告诉你的那样共享 create table 语句。
  • 按原样提供每一个有价值的信息,不要描述它,这样人们可以更好地帮助你,避免混淆。
  • 我在原帖中添加了表结构、分区信息和主键。查询运行 8 小时,因为该表有 270 GB 大并且有超过 26 亿条记录。我们今天运行了两个查询:select * from sensor_log where ts = '2014-10-26 02:39:33' 为 device_id 486 返回了 2 条记录。select * from sensor_log where ts = '2014-10-26 02:39:33' and device_id = 486 返回了 1 条记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-09
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多