- 项目介绍
- 快速开始
- 当前功能
- 数据库兼容性
- 核心概念
- 安装与启动
- 使用流程
- 结果与日志文件
- 日志和监控
- 修复 SQL
- HTTP API 概览
- 身份识别与审计
- 常见问题
- 最佳实践
- 当前未实现或限制
- 开发与验证
db-check 是一个面向数据迁移、数据同步和数据库运维场景的数据一致性核对平台。项目使用 Go 编写,提供 Gin HTTP API 和内置 Web 管理页面,可以集中管理数据源、核对任务、执行进度、差异明细和任务日志。
在数据库迁移或同步链路中,“两边行数相同”并不代表数据完全一致,仍可能存在记录缺失、目标端多数据、同一主键内容不同,以及过滤范围配置错误等问题。对大表直接编写临时 SQL 或导出文件人工比较,不仅耗时,也很难重复执行和追踪结果。db-check 将源端作为核对基准,读取源表和目标表的数据,通过主键或自定义唯一键匹配记录,给出以下结果:
- 两端内容一致的记录数
- 主键相同但字段内容不同的记录
- 仅存在于源端的记录
- 仅存在于目标端的记录
- 两端总行数及任务、分片执行状态
平台只读取业务数据库,不会自动修改目标端数据。发现差异后,可以在页面查看和人工复核,也可以通过 API 生成参考修复 SQL,审核后再由使用者决定是否执行。
- 数据迁移验收:验证迁移前后的表数据是否完整,定位漏迁、重复或内容变化的记录。
- 数据同步核验:检查同步链路两端在指定条件范围内是否一致,辅助排查同步延迟、过滤错误或异常中断。
- 异构数据库比对:在 MySQL、Oracle、PostgreSQL、SQL Server、Doris、OceanBase 等不同数据库之间按公共字段进行核对。
- 大表核对:按行数、数值范围或时间范围拆分子任务,结合并发控制降低单次全表处理压力。
- 动态数据复核:对首次发现的差异再次按键读取,过滤核对过程中数据变化造成的瞬时差异。
- 结果留痕:保存任务配置、状态、统计、差异明细、操作审计和任务日志,便于复盘。
- 数据库迁移、云迁移或机房迁移后的全量数据验收
- MySQL 与 OceanBase、Doris 等系统之间的数据同步核对
- Oracle、PostgreSQL、SQL Server 与其他数据库之间的异构迁移验证
- 主备库、历史库、归档库或数仓明细表的阶段性一致性检查
- 按日期、状态或业务条件核对部分数据
- 需要对差异记录进行分页查看、人工复核和生成参考修复 SQL 的运维流程
- 持续实时 CDC、数据复制或秒级监控;本项目是批量核对工具,不是同步引擎。
- 自动比对和迁移表结构、索引、约束、存储过程等数据库对象;当前只核对表数据。
- 无人审核的自动数据修复;系统只生成参考 SQL,不会自动执行。
- 没有稳定主键或唯一业务键的逐行核对;此类表只能使用
count模式,或先确定可靠的custom_keys。
当前管理页面支持 MySQL、OceanBase、Doris、Oracle、PostgreSQL 和 SQL Server。后端还包含 PolarDB、TDSQL-C 以及部分数据库类型别名。源端和目标端可以是不同类型的数据库,但字段名称、业务含义和可比较的数据表示需要兼容,建议在正式执行前先使用“检查配置”验证。
- 在 MySQL 中创建元数据库,并执行
sql/init.sql。 - 在
db_check同目录准备config.ini,填写元数据库连接信息和 HTTP 端口。 - 编译并启动服务:
go build -o db_check ./cmd && ./db_check。 - 打开
http://127.0.0.1:8080/home,创建源端和目标端数据源并测试连接。 - 在“库任务”或“表任务”中填写核对配置,先执行“检查配置”,再提交任务并查看结果。
任务创建后由 Planner 按分钟调度;首次使用时可以先用少量数据和 count 模式验证元数据库、数据源和权限配置。
- 数据源管理:新增、编辑、删除、启停和连接测试
- 库任务:选择多个同名表,批量生成表任务
- 独立表任务:支持源表名与目标表名不同
- 两种核对模式:逐行核对和仅行数核对
- 按行数、数值区间或时间区间拆分子任务
- 全局并发、单源并发和单表子任务并发控制
- 暂停、恢复、终止、克隆和多种重跑方式
- 自动复核与差异明细人工复核
- 差异分页查看及修复 SQL 下载接口
- 表任务日志查看和元数据库归档
- 可选的请求头身份识别及 API 审计日志
管理页面可选择以下 db_type:
db_type |
核对引擎 | 列举表 | 页面连接测试 | 任务中的“库名”含义 |
|---|---|---|---|---|
mysql |
支持 | 支持 | 支持 | 数据库名 |
oceanbase |
支持 | 支持 | 支持 | 数据库名 |
doris |
支持 | 支持 | 支持 | 数据库名 |
oracle |
支持 | 支持 | 支持 | Schema/Owner;数据源的 database_name 填 Service Name |
pgsql |
支持 | 支持 | 支持 | Schema,通常填 public;数据源的 database_name 填实际数据库名 |
sqlserver |
支持 | 支持 | 暂不支持 | Schema,通常填 dbo;数据源的 database_name 填实际数据库名 |
后端核对引擎还识别 postgres、postgresql、mssql 别名,以及 MySQL 兼容的 polar、tdsqlc。这些值未全部出现在页面选项中,且连接测试接口也未全部支持,通常应使用表中的标准值。
任务创建接口要求源端和目标端的“库名”非空;对于 PostgreSQL 和 SQL Server,这个字段实际表示 Schema,因此需要显式填写 public、dbo 或业务使用的 Schema。
所有引擎均实现了元数据读取、流式取数、行数统计、分片和按键复核。实际可用性仍取决于数据库版本、字段类型、驱动兼容性和账号权限,上线前应使用页面中的“检查配置”进行预检。
库任务 check_db_tasks
└─ 表任务 check_tb_tasks
└─ 子任务 check_tb_sub_tasks
- 库任务:保存一组公共配置。创建时,
selected_tables中每个准确表名会生成一个源/目标同名的表任务。 - 表任务:当前调度器的最小执行单位。也可以脱离库任务单独创建,此时允许源表名和目标表名不同。
- 子任务:表任务在准备阶段按切分范围生成;不配置切分字段时只生成一个子任务。
当前版本不会展开 order_{00..09} 之类的表名模式。库任务如需核对不同名表,应创建独立表任务。
| 模式 | 行为 | 差异明细 |
|---|---|---|
default |
按主键/自定义键读取两端数据,计算行摘要并比较 | 记录内容不一致、仅源端存在、仅目标端存在 |
count |
分别执行行数统计 | 不记录逐行差异 |
default 模式要求源表存在主键,或配置逗号分隔的 custom_keys。自定义键必须能唯一标识记录,否则相同键会覆盖比较暂存数据,结果不可靠。
比较过程使用本地 Pebble 临时库完成无序数据归并,结束后清理临时目录;最终差异保存在 SQLite 中,因此运行目录需要预留足够磁盘空间。
where_condition:不带WHERE关键字的 SQL 条件,最长 500 个字符,同时用于源端和目标端。custom_keys:逗号分隔的自定义唯一键;留空时使用源表主键。exclude_columns:逗号分隔的不参与内容比较的字段。键字段仍会用于记录匹配。- 目标表必须包含源表中未排除的字段。建议先执行“检查配置”,验证键、字段和分片范围。
留空 split_column 时执行单个全表子任务。填写切分字段后,split_size 支持:
| 格式 | 含义 | 示例 |
|---|---|---|
<正整数>r |
按大约指定行数寻找分片边界 | 1000000r |
<正整数> |
数值字段按固定步长切分 | 100000 |
<正整数>h |
时间字段按小时切分 | 12h |
<正整数>d |
时间字段按天切分 | 7d |
<正整数>m |
时间字段按月切分 | 1m |
<正整数>y |
时间字段按年切分 | 1y |
库任务可将 split_column 设置为 __pk1__(别名 primary_key_first),为每张表自动选择源表第一个主键字段。此时 split_size 留空会使用 1000000r;填写纯数字也会按行数处理并自动补 r。
建议选择有索引、非空且分布合理的字段。页面只对配置了切分字段的运行中表任务显示“暂停”,因为暂停是等待当前子任务结束后停止后续分片。
default 模式发现差异后,会再次按键读取两端数据,以过滤核对期间数据变化导致的瞬时差异:
max_recheck_times:最大自动复核轮数;小于等于 0 时关闭。max_recheck_rows:待复核差异数上限;超过上限会跳过自动复核。- 自动复核通过的记录会从差异库移除,并累计到
recheck_pass_rows。 - 页面差异抽屉还支持对当前页或选中记录执行人工复核。
- Go 1.25 或更高版本(以
go.mod为准) - 一个 MySQL 元数据库
- 到源端和目标端数据库的网络连通性及只读查询权限
- 运行用户对程序目录有写权限,用于创建
data/、logs/及gorm.log、http.log - 没有固定的 CPU、内存和磁盘最低值;资源需求取决于表大小、差异数量和并发设置
前端资源已包含在 web/,不需要 Node.js 或单独构建前端。
先创建数据库,再执行完整建表脚本:
CREATE DATABASE db_check_meta CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;mysql -h 127.0.0.1 -P 3306 -u root -p db_check_meta < sql/init.sql服务不会自动迁移表结构,已有环境升级时也需要人工核对并应用 sql/init.sql 中的最新字段和表。
secret_keys 中 access_key='default' 的记录用于加密数据源密码。初始化脚本包含示例密钥,生产环境必须在录入数据源之前替换,并妥善备份;密钥变化后,原有密码将无法正常解密。
编辑可执行文件同目录下的 config.ini:
http_port = 8080
concurrency = 8
source_concurrency = 1
http_auth_enabled = false
[db]
host = "127.0.0.1"
port = 3306
user = "db_check"
password = "请替换"
database = "db_check_meta"| 配置项 | 默认值 | 作用 |
|---|---|---|
http_port |
8080 |
HTTP 监听端口 |
concurrency |
2 |
同时运行的表任务 worker 数 |
source_concurrency |
1 |
同一个源数据源同时运行的表任务数 |
http_auth_enabled |
true |
是否要求 API 请求携带身份请求头 |
[db] |
无 | MySQL 元数据库连接信息 |
go build -o db_check ./cmd
./db_check程序启动后会自动切换到可执行文件所在目录,因此 config.ini 和 web/ 需要与部署后的 db_check 放在同一个目录层级;data/、logs/ 会在运行过程中按需自动创建。
页面地址:http://127.0.0.1:8080/home
也可以使用仓库提供的简单管理脚本:
./admin.sh start
./admin.sh status
./admin.sh stopadmin.sh 通过进程名查找 db_check,不适合在同一主机运行多个同名实例。反向代理示例见 nginx_config.md。
仓库的 GitHub Actions 会在推送 v 开头的标签时自动运行测试,并为 Linux、macOS、Windows 的 amd64 和 arm64 生成完整安装包、SHA-256 校验文件及 GitHub Release。例如发布 v1.0.1:
git tag -a v1.0.1 -m "Release v1.0.1"
git push origin main
git push origin v1.0.1安装包包含可执行文件、Web 静态资源、初始化 SQL 和示例配置;Linux/macOS 包还包含 admin.sh 管理脚本。Windows 包中的程序名为 db_check.exe。首次启动前应修改包内的 config.ini。标签一旦推送便会触发公开发版,因此应先确保主分支代码和版本号正确。
典型部署目录如下,data/ 和 logs/ 会在运行时自动创建:
db-check/
├── db_check
├── config.ini
├── admin.sh
├── web/
├── data/ # 结果 SQLite 和临时文件
├── logs/ # 表任务日志
├── gorm.log
├── http.log
└── running.log # 使用 admin.sh 启动时产生
大表默认模式会同时产生源端和目标端的临时 Pebble 数据,磁盘空间应按并发子任务和差异数据量预留。并发调高后,源库连接数、网络带宽、服务端内存和临时磁盘占用都会增加,应先在测试环境压测再调整。
在“数据源”页面创建源端和目标端连接:
- 角色可选
source、sink或both。 - 新增时密码必填;编辑时密码留空表示保留原密码。
database_name是建立连接时使用的数据库名或 Oracle Service Name。extra必须是 JSON 对象字符串;当前核对引擎不依赖旧文档中 Doris FE HTTP 地址等扩展参数。- SQL Server 当前不能通过“测试连接”按钮验证,但核对引擎本身已实现。
| 类型 | 数据源 database_name |
任务中的源库/目标库字段 | 说明 |
|---|---|---|---|
| MySQL / OceanBase / Doris | 实际数据库名 | 数据库名 | 表名按数据库查询 |
| Oracle | Service Name | Schema/Owner | Oracle 表名通常按 Owner 查询 |
| PostgreSQL | 实际数据库名 | Schema,通常为 public |
任务库名不能为空 |
| SQL Server | 实际数据库名 | Schema,通常为 dbo |
当前页面连接测试未接通 |
核对引擎只读取源端和目标端的表结构及数据,不会执行 INSERT、UPDATE 或 DELETE。源端、目标端账号至少需要连接、查询表数据和读取元数据的权限;元数据库账号则需要读写 sql/init.sql 创建的任务、数据源、日志和审计表。
有两种方式:
- 在“库任务”中选择源/目标数据源、库名和多个表。每个选中表立即生成一个同名表任务。
- 在“表任务”中直接创建独立任务。目标表名留空时默认使用源表名,也可以显式指定不同名称。
提交前使用“检查配置”确认:
- 两端连接和表可访问;
- 主键或自定义键有效;
- 目标端未缺少待核对字段;
- 分片参数可解析,并可查看预计子任务数。
启用的 pending 表任务由 Planner 每分钟整点扫描一次,新任务通常需要等待最多约 60 秒。当前查询只扫描最近 7 天创建的任务;超过 7 天的待执行任务不会被自动调度。
表任务有两个独立状态字段:
准备状态 prepare_phase
init:尚未准备preparing:读取表结构并生成子任务prepared:准备完成failed:准备失败
执行状态 status
pending:等待 Planner 调度queueing:已提交调度器running:执行中completed:执行完成failed:执行失败paused:已暂停stopped:已终止
完成后,check_result 为 consistent 或 inconsistent;失败或终止时为 unknown。库任务状态和一致/不一致表数由其表任务实时汇总,并不是单独执行的准备状态机。
子任务状态 check_tb_sub_tasks.status
pending:等待表任务启动running:正在读取和比较当前分片completed:分片完成,统计结果已保存failed:分片执行失败,可通过表任务重试失败分片paused:收到暂停信号,尚未完成的分片等待恢复stopped:收到终止信号,分片被强制停止
子任务的 check_result 同样会记录 consistent、inconsistent 或 unknown。表任务汇总结果来自所有子任务及其本地结果库。
- 暂停:停止启动新的子任务,让已开始的子任务结束后进入
paused。 - 恢复:将暂停的表任务及其暂停子任务重置为
pending,等待下一轮调度。 - 终止:取消正在执行的数据库操作,任务进入
stopped。 - 重新开始:删除现有子任务和 SQLite 结果,从头准备、执行。
- 继续执行:保留已完成分片,仅继续尚未完成的分片,不重试失败分片。
- 重试失败分片:保留已完成分片,将失败分片重置后继续执行。
库任务的暂停、恢复和终止会作用于其子表任务。只有完成、失败或终止的库任务可以删除;表任务只能在非排队、非运行状态编辑或删除。
表任务页面展示:
- 源端/目标端行数
- 一致行数
- 内容不一致行数
- 仅源端存在行数
- 仅目标端存在行数
- 执行耗时、错误信息、子任务和任务日志
点击差异数量可以分页查看键值和两端字段差异,也可以按子任务过滤。当前版本没有 CSV 导出功能。
所有相对路径均以可执行文件所在目录为基准:
| 路径 | 内容 |
|---|---|
data/<tb_task_id>/<source_table>.db |
表任务的 SQLite 差异明细和摘要 |
data/<tb_task_id>/tmp/<sub_task_id>/ |
Pebble 比较暂存目录,正常结束后自动清理 |
logs/<tb_task_id>.log |
表任务详细日志 |
running.log |
使用 admin.sh start 时的进程标准输出/错误 |
http.log |
Gin HTTP 访问日志 |
gorm.log |
元数据库 GORM 日志 |
表任务进入 completed、failed、paused 或 stopped 后,完整任务日志还会写入元数据库的 check_tb_task_logs 表。
不要在任务运行中移动、删除或共享写入 SQLite/Pebble 文件。备份时应同时保留元数据库与 data/,否则页面无法读取历史差异。
任务日志按表任务 ID 保存,可以直接查看运行过程:
tail -f logs/123.log
tail -n 100 logs/123.log
grep -i "error\|failed" logs/123.log已结束的表任务还可以通过 GET /api/check-tb-tasks/:id/log 读取归档日志。http.log 用于排查接口请求,gorm.log 用于排查元数据库读写。
curl 'http://127.0.0.1:8080/api/scheduler-stats'返回值包括就绪队列长度、全局并发数、单源并发数、排队任务数、运行任务数以及按数据源划分的待执行数量。启用 HTTP 身份识别时,需要同时携带 X-User-ID 请求头。
- 长时间停留在
pending或queueing的任务 failed任务及其error_message- 源库连接失败、权限错误和目标表字段缺失
data/所在磁盘空间和 Pebble 临时目录清理情况- 源库连接数、查询耗时和线上业务负载
修复 SQL 目前通过 API 按差异类别和分页下载,管理页面尚未提供入口:
curl -X POST 'http://127.0.0.1:8080/api/check-results/123/repair-sql' \
-H 'Content-Type: application/json' \
-d '{"diff_type":"source_more","page":1,"page_size":100}' \
-o repair.sql差异类型与生成语句:
source_more:生成INSERTtarget_more:生成DELETEdiff:生成UPDATE
接口只处理请求指定的一页,不会自动保存 SQL 到 data/。生成器使用通用 SQL 文本,没有完整覆盖各数据库的标识符、保留字和特殊字段类型规则;执行前必须人工审核,并建议先在测试环境验证。
页面路由:
GET /home:主页面GET /tb-sub-tasks:子任务页面GET /static/*、GET /components/*:静态资源
主要 API:
POST /api/ping:连接测试POST /api/get-tables:列举数据源中的表/api/data-sources:数据源 CRUD/api/check-db-tasks:库任务 CRUD、克隆、暂停、恢复、终止/api/check-tb-tasks:表任务 CRUD、克隆、恢复、重跑、日志POST /api/check-tb-tasks/test-config:任务配置预检GET /api/check-tb-sub-tasks:查询子任务/api/check-results/:tb_task_id/*:摘要、三类差异、人工复核和修复 SQLGET /api/scheduler-stats:调度队列与并发统计/api/users:用户查询和更新
查询已完成的表任务:
curl 'http://127.0.0.1:8080/api/check-tb-tasks?page=1&page_size=50&status=completed'查询单个表任务的结果摘要:
curl 'http://127.0.0.1:8080/api/check-results/123/summary'对指定差异记录执行人工复核:
curl -X POST 'http://127.0.0.1:8080/api/check-results/123/recheck' \
-H 'Content-Type: application/json' \
-d '{"diff_type":"diff","detail_ids":[1001,1002]}'库任务的常用操作路径如下:
| 操作 | 方法和路径 |
|---|---|
| 创建库任务 | POST /api/check-db-tasks |
| 更新/删除库任务 | PUT/DELETE /api/check-db-tasks/:id |
| 克隆库任务 | POST /api/check-db-tasks/:id/clone |
| 暂停/恢复/终止库任务 | POST /api/check-db-tasks/:id/{pause,resume,stop} |
| 创建表任务 | POST /api/check-tb-tasks |
| 更新/删除表任务 | PUT/DELETE /api/check-tb-tasks/:id |
| 重跑表任务 | POST /api/check-tb-tasks/:id/recheck |
| 恢复暂停的表任务 | POST /api/check-tb-tasks/:id/resume |
| 查询子任务 | GET /api/check-tb-sub-tasks |
| 查询三类差异 | GET /api/check-results/:id/{diff,source-more,target-more} |
启用 http_auth_enabled 时,所有 /api 请求都需要由上游注入 X-User-ID;写请求还应由上游系统限制为有权限的操作人员。
db-check 不提供登录页、密码校验、Token 签发或会话管理。鉴权由 Nginx、SSO、统一认证网关等可信上游系统完成,后端只负责读取上游注入的用户身份,并将身份用于任务创建人和审计记录。
请求链路如下:
浏览器
│ 登录凭证 / Cookie / Token
▼
反向代理或认证网关
│ 验证身份,通过后注入 X-User-ID
▼
db-check
├─ 静态页面和静态资源:直接提供
└─ /api/*:身份识别 + HTTP 审计
启用 http_auth_enabled = true 时,所有 /api/* 请求必须包含非空的 X-User-ID,否则后端返回 401 Unauthorized:
X-User-ID: 用户唯一标识(必填)
X-User-Name: 用户展示名(可选)
后端信任收到的 X-User-ID,不会自行验证 Cookie、JWT 或 Token。因此服务端口不能直接暴露给不可信客户端,否则客户端可以伪造请求头。生产环境应只允许可信反向代理访问后端,并在代理层覆盖客户端自行传入的 X-User-ID 和 X-User-Name。
http_auth_enabled = truetrue:/api/*先执行身份识别;缺少X-User-ID时返回 401。false:关闭身份识别,API 直接放行;请求仍会写入审计日志,但没有关联用户 ID。
静态页面、/static/* 和 /components/* 不经过身份识别中间件。是否限制页面访问,应由反向代理根据部署环境决定。
下面示例假设认证服务能够通过 2xx 表示认证成功,并在响应头中返回 X-User-ID。认证接口地址、登录跳转地址和后端地址需要替换为实际值:
# 认证子请求,不直接暴露给客户端
location = /internal/db-check-auth {
internal;
proxy_pass http://auth-server:8888/user/authInfo;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Cookie $http_cookie;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Real-IP $remote_addr;
}
# API 需要认证,并将认证服务返回的用户 ID 传给 db-check
location /db-check/api/ {
auth_request /internal/db-check-auth;
auth_request_set $auth_user_id $upstream_http_x_user_id;
auth_request_set $auth_user_name $upstream_http_x_user_name;
proxy_set_header X-User-ID $auth_user_id;
proxy_set_header X-User-Name $auth_user_name;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080/api/;
}
# 非 API 页面和静态资源按部署策略决定是否开放
location /db-check/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080/;
}认证失败时,Nginx 通常返回 401 或 403;如果需要跳转到统一登录页,应在 Nginx 中配置 error_page 或命名 location。后端本身不会跳转登录页。
开启身份识别后,每个首次出现的 X-User-ID 会自动创建 users 记录;已有用户只更新 last_seen_at。X-User-Name 只用于首次创建时填写 name,不会在每次请求中覆盖已有名称。
users 表主要字段:
| 字段 | 含义 |
|---|---|
user_id |
上游传入的用户唯一标识,唯一索引 |
name |
展示名 |
is_admin |
管理员标记 |
last_seen_at |
最近一次通过身份识别的时间 |
当前路由没有挂载 RequireAdmin 中间件,is_admin 目前不会自动限制数据源、任务或用户管理接口。也就是说,身份识别和管理员授权是两件事:前者由后端实现,后者目前应由反向代理、网关或后续路由权限改造负责。
通过身份识别的 /api/* 请求会继续经过 AuditMiddleware,并异步写入元数据库的 http_audit_logs 表。缺少 X-User-ID 而被身份中间件直接拒绝的请求会在更早阶段返回 401,不能依赖应用审计表记录这类请求;如需记录所有认证失败,应在 Nginx 或认证网关侧记录。记录内容包括:
user_id:身份识别得到的用户 IDclient_ip:客户端 IPmethod、path、route_pattern、query_stringstatus_code、success、duration_msrequest_body_summary、response_body_summaryerror_message、created_at
请求和响应摘要最多保留 512 字节;只有 POST、PUT、PATCH 请求会读取请求体摘要。/api/ping 的请求体固定记录为 [masked],避免把数据源密码写入审计表。审计写入采用异步数据库操作,接口响应不会等待日志 INSERT 完成;数据库故障时不应把审计记录视为绝对可靠的同步交易记录。
查询最近审计记录示例:
SELECT id, user_id, method, path, status_code, success, duration_ms, created_at
FROM http_audit_logs
ORDER BY id DESC
LIMIT 100;pending任务由 Planner 每分钟整点扫描,刚创建后等待几十秒属于正常现象。- Planner 只调度启用状态且最近 7 天创建的
pending表任务。 queueing通常表示全局 worker 或该源数据源的并发额度已用满,可通过/api/scheduler-stats查看队列。
先查看表任务日志和 error_message,重点检查源/目标表是否存在、账号是否能读取元数据、表是否有主键、目标端是否缺少待核对字段,以及分片字段和 split_size 是否有效。
default 模式要求源表有主键,或者在 custom_keys 中填写逗号分隔的唯一键。没有可靠唯一键时只能做 count 模式的行数核对;不要使用可能重复的普通字段作为自定义键。页面“检查配置”仍会读取并校验表元数据。
确认源端和目标端使用了相同的 where_condition,并排除同步延迟、时区/类型转换、字符集差异和核对期间持续写入等因素。可以配置 max_recheck_times 进行自动复核,但超过 max_recheck_rows 的差异会被跳过,需要人工处理。
暂停会等待已启动的工作结束,终止会尽快取消正在执行的数据库操作。continue 保留已完成分片,retry 只重置失败分片,restart 会删除原有子任务和结果文件后重新执行。大表建议配置切分字段,以便分片级暂停和重跑。
结果文件位于 data/<tb_task_id>/。任务尚未完成、结果目录被手工删除,或使用 restart 重跑时清理了旧结果,都会导致历史差异无法查询。请不要在任务执行期间移动或删除 data/。
SQL Server 的核对引擎、列举表和查询能力已经实现,但当前 /api/ping 的连接测试类型列表尚未包含 SQL Server。可以先用“检查配置”验证实际任务连接。
- 优先选择稳定唯一键:使用主键或真正唯一的业务键,避免用状态、时间等重复字段作为
custom_keys。 - 给键和切分字段建索引:切分字段应尽量非空、分布均匀,避免用低基数字段导致大量扫描。
- 先行数、后逐行:迁移验收可先执行
count模式确认范围和行数,再使用default模式定位具体差异。 - 固定核对范围:对持续写入的业务表使用明确的时间或业务条件,尽量采用左闭右开区间,避免相邻批次重复或遗漏。
- 控制并发:先以较低的
concurrency、source_concurrency和subtask_concurrency验证负载,再逐步提高;优先保护生产源库。 - 为动态数据预留复核:数据核对期间无法停止写入时,配置合理的自动复核次数和行数上限,并人工检查未复核的大批量差异。
- 预留本地磁盘:默认模式会写入结果 SQLite 和临时 Pebble 数据,差异越多、并发越高,临时空间需求越大。
- 保存配套数据:备份历史结果时同时保存元数据库和
data/目录;只备份其中一部分无法完整恢复任务和差异。 - 先检查再执行:正式运行前使用“检查配置”确认连接、表结构、键、字段和预计分片数量。
- 修复前人工审核:生成的 SQL 只是参考脚本,不会自动执行,也不保证覆盖所有数据库方言和特殊字段类型。
- 没有定时执行计划或时间窗口;任务只有“创建后进入待执行队列”的模式。
- 没有 QPS/带宽限流;只有并发数控制。
- 不支持表名表达式或范围展开,只接受准确表名数组。
- 不支持 CSV 差异导出。
- 修复 SQL 只有下载 API,页面无入口,也不会自动执行 SQL。
- 没有自动数据库迁移,元数据库表结构必须人工维护。
- SQL Server 的连接测试接口尚未接通。
table_concurrency不控制当前按表任务调度路径。- Planner 不会调度创建时间超过 7 天的
pending表任务。
go test ./...
go vet ./...项目入口为 cmd/db_check.go,HTTP 路由集中在 server/enter.go,数据库核对实现位于 engine/,核心执行流程位于 checker/,元数据库初始化脚本为 sql/init.sql。