这是一篇关于跨不同 SQL 数据库进行差异比较的内容,主要面向对数据库内部感兴趣的软件和数据工程师,内容探索了其中涉及的不寻常挑战和解决方案,包含以下主要方面:
- 引言:在数据工程领域,比较数据集很有用,如验证数据迁移等,但跨不同数据库时会更复杂,文中介绍了 2022 年创建跨数据库差异比较工具的项目,面临网络、数据库标准差异、数据库设计等挑战,最终创建了高效工具,接下来将介绍实现细节和算法。
- 算法概述:分而治之:通过比较数据的哈希值来检测差异,基本过程是哈希两个表,若不同则分割成小片段重复操作,该算法虽简单但不能完全用 SQL 实现,选择 Python 作为主要语言。
计算哈希的部分:
- MD5 救援:MD5 是常用哈希函数,但 SQL Server 的 MD5 函数很慢,因此放弃对其支持。
- 和可能溢出:SQL 中的 MD5 函数只能处理列数据,需将 MD5 值相加,许多数据库的 SUM 函数可能溢出,解决方案是截取 MD5 值的低 60 位并限制每批求和的行数。
- 列值需要标准化:MD5 函数处理字符串,不同数据库中相同值的字符串表示可能不同,需对布尔值、数字(包括精度处理)、时间戳等类型进行标准化。
分割表的部分:
- 调整期望:在 SQL 数据库中,OFFSET 是 O(n)操作,不适合全表分页,现代网站使用键集分页,Reladiff 为并行处理需知道键集列的锚点值,选择键集分段方式。
- 键集分段:键集分页适合逐页读取,Reladiff 需并行查询页面,通过获取键集列的 min 和 max 值分段,性能优于键集分页但有页面大小不固定等缺点。
- 值分布:假设主键有均匀分布,但实际中存在非均匀分布,如 UUID、字母数字字符串、复合键等,可能导致页面大小不均匀影响性能,有采样和动态更新二分参数等解决方案。
- 字母数字和 UUID:UUID 存储为字符串或原生类型,在不同数据库间复制时需标准化,字母数字键也需处理不同的存储规则和排序方式。
- 复合键:复合键跨多列,可按第一列分段但可能性能不佳,支持复合键可更好地捕获行的真实标识,通过将复合键视为向量空间进行分段。
实现差异的部分:
- 二分因子和阈值:二分因子决定每次分割的段数,默认 32 是常见用例的良好平衡,二分阈值决定何时下载段而不是继续分割,默认 16K 行基于经验测试,用户可根据网络速度调整。
- 多线程:多数经典数据库单线程执行查询,表分割可并行化算法提高性能,但需注意数据库负载,云数据库可自行并行化。
- 重复行:处理无约束主键或重复主键的表时,差异比较需计算唯一项计数,极端情况下数千个重复行可能影响差异速度。
- 模式协商:在开始差异比较前查询两个表的模式,了解列类型、精度等,以正确标准化值和处理文本列,大多数数据库支持相似的模式查询接口,但也有差异。
- 急切差异(或立即开始):分割表的第一步是查询两个表的最小/最大值范围,可利用一个表先返回范围的优势,避免等待两个表都返回再开始差异比较。
- 可能时使用 JOIN:当表在同一数据库中时,使用 OUTER JOIN 比哈希和二分更快,但大型表的 JOIN 可能超时,可并行运行 JOIN 并在之前对表进行二分。
- 结论:Reladiff 成为生产就绪经历了漫长挑战,通过创造性解决方案和细节关注取得了显著性能提升,表分割是高效技术,可用于多种数据库任务,未来数据库工具的实现仍有挑战,但前景乐观,可查看 Reladiff 的文档和 GitHub 仓库了解更多,如有需要可联系咨询。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。