datakit7.0.0rc3迁移PG后,部分表出现重复数据

使用datakit7.0.0RC3版本迁移PG13数据到GS603,部分表出现重复数据。

1、迁移物理表总量

约1500多张

2、存在问题物理表

约30多张

3、问题举例

源数据库表sp_dxryxxb:记录行数为8896行(注:pg13源表是有主键,数据是唯一的)

表DDL:

CREATE TABLE public.sp_dxryxxb (
id varchar(36) NOT NULL DEFAULT uuid_generate_v4(),
–约100个字段定义,字段类型主要是varchar、int8、numeric、timestamp–
CONSTRAINT sp_dxryxxb_pkey PRIMARY KEY (id)
);
CREATE INDEX “idx$$_8e3c0001” ON public.sp_dxryxxb USING btree (userid, id);

迁移后GS库表sp_dxryxxb:记录行数为13344行。

经sql统计发现迁移后的数据表:4448行无重复,另外4448行重复了一次

所以:13344=4448(不重复)+4448*2(重复一次)

查阅迁移日志,关于该表的迁移日志只有一个错误:

16:36:04.494 [worker-3] ERROR org.full.migration.target.TargetDatabase – write table primary key has occurred an exception, detail:[..37.149:51146/..37.149:15000] ERROR: could not create unique index “sp_dxryxxb_pkey”

同样的上述错误出现了37次,涉及37张表。

请问上述迁移出现重复数据的问题如何处置?

答案内容由AI生成,仅供参考:

:white_check_mark: 总结

问题 原因 解决方案
部分表出现重复数据 唯一索引创建失败导致主键约束失效 手动去重 + 重建唯一索引
错误日志:“could not create unique index” 索引创建失败(权限、冲突、数据重复等) 检查索引状态、预建索引
重复数量规律性强(n×2) 极可能是写入重试机制导致重复 优化 DataKit 并发写入策略
使用 RC 测试版工具风险高 存在已知 bug 或未完善逻辑 升级至稳定版本

:white_check_mark: 最终建议:

  1. 立即对受影响表进行 数据去重 + 唯一索引重建
  2. 对未来迁移任务采用 预建表 + 显式主键约束 方式
  3. 升级至 DataKit 稳定版本,并启用 迁移后数据校验
  4. 记录此类案例,作为企业数据迁移标准操作流程的一部分
点击此处查看详细分析解答

DataKit 7.0.0-RC3 迁移 PostgreSQL 13 至 openGauss 6.0.3 出现重复数据问题分析与解决方案

根据您提供的信息,使用 DataKit 7.0.0-RC3 将 PostgreSQL 13 数据库迁移至 openGauss 6.0.3 时,约有 30 多张表出现重复数据现象。以表 sp_dxryxxb 为例,源端记录数为 8,896 行,目标端变为 13,344 行,且呈现 4,448 行唯一 + 4,448 行重复一次 的规律。迁移日志中大量报错“无法创建唯一索引”(could not create unique index "sp_dxryxxb_pkey")。以下是对该问题的综合分析和处置建议。


:magnifying_glass_tilted_left: 问题根本原因分析

1. 主键唯一索引创建失败导致重复插入

从迁移日志关键错误:

ERROR: could not create unique index “sp_dxryxxb_pkey”

可以明确:在目标数据库(openGauss)上未能成功创建主键约束对应的唯一索引

结合表结构:

CONSTRAINT sp_dxryxxb_pkey PRIMARY KEY (id)

这本应自动创建一个 唯一索引(Unique Index) 来保证 id 字段的唯一性。

但由于某种原因(如索引已存在但损坏、字段类型不兼容、权限不足、系统资源限制等),该唯一索引创建失败,导致:

  • 主键约束未被强制执行
  • 数据写入时未检测到重复主键
  • 相同主键的数据被允许重复写入
  • 最终造成表中部分数据重复

:pushpin: 结论:索引创建失败 → 唯一性约束失效 → 重复数据写入


2. 重复模式分析:4448 × 2 = 8896(接近源数据总量)

您观察到的结果非常关键:

类型 行数
不重复数据 4,448
重复行(每条2次) 4,448 × 2 = 8,896
总计 13,344

而原始数据总量为 8,896 行,恰好是 4,448 × 2

这强烈暗示一种可能的情况:

:light_bulb: DataKit 在执行数据写入时,对同一份数据进行了两次写入尝试,且因无唯一索引保护,导致部分数据被重复插入一次

此类行为常见于:

  • 并发写入冲突或连接超时后重试
  • 分片任务划分异常
  • 检查点(checkpoint)机制异常导致重复拉取
  • 数据写入成功但确认失败,引发重传

但最关键的前提是:缺少唯一索引保护


3. 为什么 Unique Index 创建失败?

结合知识库及 openGauss 特性,可能原因包括:

:white_check_mark: 知识库支持点:

  • Unique Index 确保所有列值不同(Entity 描述)
  • Datakit6.0OpenGauss 迁移时存在执行异常
  • openGauss 对 SQL 兼容性并非完全等同 PostgreSQL

可能原因分析:

原因 说明
1. UUID 函数不兼容 源表使用 uuid_generate_v4() 生成主键 ID,但 openGauss 默认可能未启用 uuid-ossp 扩展或不支持此函数,导致生成异常或冲突
2. 主键字段类型映射异常 varchar(36) 虽然可用作 UUID 存储,但在索引构建时可能存在字符集或排序规则(collation)问题
3. 目标表空间或索引名冲突 同名索引已存在但状态异常,或表空间不足,导致新索引创建失败
4. 权限不足 执行用户缺少创建索引权限
5. 并发建索引发冲突 多个子任务并发建索,导致资源争抢或死锁

:white_check_mark: 解决方案与操作步骤

:white_check_mark: 步骤一:验证目标端主键约束是否生效

在 openGauss 目标库中执行:

\d+ sp_dxryxxb

查看输出是否包含:

CONSTRAINT sp_dxryxxb_pkey PRIMARY KEY, btree (id)

若没有,则说明:

  • 主键未建立
  • 或建表时跳过约束
  • 此时表无唯一性保障

也可查询系统表确认:

SELECT conname, contype 
FROM pg_constraint 
WHERE conrelid = 'sp_dxryxxb'::regclass AND contype = 'p';

如果没有结果,说明主键未创建。


:white_check_mark: 步骤二:手动尝试重建唯一索引(测试可行性)

执行:

CREATE UNIQUE INDEX CONCURRENTLY sp_dxryxxb_pkey_manual 
ON sp_dxryxxb(id);

使用 CONCURRENTLY 避免锁表

观察结果:

  • 成功 → 说明当前数据已有重复,无法建立唯一索引
  • 失败并提示 duplicate key → 明确存在重复主键
  • 成功后可添加主键约束:
ALTER TABLE sp_dxryxxb ADD CONSTRAINT sp_dxryxxb_pkey PRIMARY KEY USING INDEX sp_dxryxxb_pkey_manual;

:white_check_mark: 步骤三:清理重复数据

若确认有重复,可使用以下 SQL 清理:

-- 先备份原表
CREATE TABLE sp_dxryxxb_backup AS SELECT * FROM sp_dxryxxb;

-- 删除重复项,保留 ctid 最小的一条(物理存储位置靠前)
DELETE FROM sp_dxryxxb 
WHERE ctid NOT IN (
    SELECT MIN(ctid) 
    FROM sp_dxryxxb 
    GROUP BY id
);

:warning: 注意:ctid 是 openGauss/PostgreSQL 的内部行标识符,仅用于此类紧急去重场景

完成后再尝试创建唯一索引。


:white_check_mark: 步骤四:修复 DataKit 迁移配置以避免再次发生

推荐措施:

  1. 升级 DataKit 至正式版

    • 当前使用的是 portalControl-7.0.0rc3-exec.jar(测试版)
    • 建议升级到 稳定版本,如后续发布的 GA 版本,修复已知并发写入与索引创建问题
  2. 确保目标库具备 UUID 支持

    • 在 openGauss 中启用兼容方式:

      CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
      
    • 或使用替代方案生成 UUID(如应用层生成)

  3. 预创建目标表结构与索引

    • 不依赖 DataKit 自动建表,改为:
      • 手动导出 DDL 并修改兼容性(如 varchartextint8bigint
      • 在目标端提前建好完整 schema(含主键、索引)
      • DataKit 仅负责数据迁移
  4. 启用迁移校验功能

    • 利用 DataKit 内置的 数据校验工具 或结合 gs_datacheck 工具进行迁移后一致性比对
    • 及时发现重复、缺失等问题
  5. 检查迁移日志中的并行策略

    • 查看是否有多个 worker 写入同一张表
    • 调整子任务并发度或启用 幂等写入模式

:hammer_and_wrench: 预防建议(长期)

措施 说明
启用兼容性模式 B openGauss 的 B 模式兼容 MySQL 行为,建议开启
统一使用小写字母命名对象 openGauss 在 B 模式下可能对大小写敏感(参考 doc_dept_dict 问题)
避免依赖序列/函数生成主键 若无法安装扩展,建议改用客户端生成 UUID
迁移前后开启慢日志监控 便于排查异常操作
使用 DataKit 的数据校验模块 迁移完成后自动对比源目数据一致性

:puzzle_piece: 补充说明:openGauss 与 PostgreSQL 兼容性差异

虽然 openGauss 源自 PostgreSQL,但已有显著差异:

  • 部分语法不兼容(如 LANGUAGE plpgsql 报错问题)
  • 扩展支持有限(如 uuid_generate_v4() 需额外安装或模拟)
  • 默认认证方式为 SHA-256,关闭 MD5
  • B 模式下大小写敏感行为变化

因此,跨平台迁移时需特别注意:

  • 函数兼容性
  • 数据类型映射
  • 约束与索引行为

:white_check_mark: 总结

问题 原因 解决方案
部分表出现重复数据 唯一索引创建失败导致主键约束失效 手动去重 + 重建唯一索引
错误日志:“could not create unique index” 索引创建失败(权限、冲突、数据重复等) 检查索引状态、预建索引
重复数量规律性强(n×2) 极可能是写入重试机制导致重复 优化 DataKit 并发写入策略
使用 RC 测试版工具风险高 存在已知 bug 或未完善逻辑 升级至稳定版本

:white_check_mark: 最终建议:

  1. 立即对受影响表进行 数据去重 + 唯一索引重建
  2. 对未来迁移任务采用 预建表 + 显式主键约束 方式
  3. 升级至 DataKit 稳定版本,并启用 迁移后数据校验
  4. 记录此类案例,作为企业数据迁移标准操作流程的一部分

如需进一步协助,建议收集:

  • pg_log 中关于索引创建失败的完整堆栈日志
  • 目标表的完整 CREATE TABLE 和索引定义
  • DataKit 子任务配置参数(并行度、写入模式)

以便深入定位根本原因。

已解决,今天之后可下新包重试,AtomGit | GitCode - 全球开发者的开源社区,开源代码托管平台