0

(tldr;我认为定期更新会强制表使用自然键。所以我必须迁移我的数据库模式。)

我有一个生产数据库,其中有一个类似planets的表,尽管它具有很好的潜在自然键(例如,永远不会真正改变的行星名称),但它使用典型的递增整数作为主键。行星表有一个或两个自引用列,例如 *parent_planet_id*。

现在我正在构建离线的基于云的工作人员,每周重新创建行星记录的子集,并且它们需要与主服务器集成。我的计划是:

  • 一个工作实例有一个迷你版的数据库(相同的模式,但没有行星记录)
  • 每周一次,工作人员启动,完成所有处理,创建其 100,000 左右的行星记录,并导出数据。(我认为导出格式对于这个特定问题并不重要:可能是 mysqldump、yaml 等)
  • 然后,生产服务器导入记录:一些是新记录,大多数是更新。

最后一步是我不知道如何解决的问题。我不是每次都完全替换行星表,所以问题是两个数据库都有自己的递增整数 PK。所以我不能只做一个简单的导入。

我考虑过在没有 id 列的情况下导出,但后来我意识到自引用列会阻止这种情况。

我看到两种可能的解决方案:

  • 重新设计架构以对行星表使用自然键。这会很痛苦。
  • 使用 UUID 而不是键的递增整数。我认为搬到那里会更容易。id 将是唯一的,并且可以安全地导入新行。这也避免了依赖于键中的自然数据的问题。
4

3 回答 3

1

修改Planets以使用交替层次结构技术,如嵌套集闭包表路径枚举而不是导出。这将打破 ID 依赖性。

或者,如果您仍然不喜欢这个想法,请将您的导出和导入视为 ETL 问题。

  • 在导出期间修改记录以包含PlanetName, ParentPlanetName
  • 首先导入所有行星 ( PlanetNames)
  • 然后导入层次结构 ( ParentPlanetName)

在任何情况下,第一个 DB 的代理键都不应该离开那个 DB——它在它之外没有任何意义。

于 2012-09-17T11:53:25.090 回答
0

最好的解决方案(就设计而言)是优化您的密钥架构并实施一些复合密钥,其中包含有关何时和从何处导入行星的信息,但您不想这样做。

更容易(我认为),但有点“快乐工程”的解决方案是修改导入密钥。例如,您可以这样做:1. 在主系统中锁定行星表(因此在导入期间不会出现新键),2. 根据主系统中的行星表创建具有两列 ID 和 PLANET NAME 的查找表,3 . 从该表中获取最大键值, 4. 通过添加在步骤 #3 中检索到的 MAX 值来增加每个导入的键(标识和引用父子行星关系)值, 5. 更改主行星表并更改当前自动增量实际 MAX + 1 值的值 6. 现在检查表(过程中的光标循环)检查当前行星名称是否在查找中有不同的键,

于 2012-09-17T15:06:56.473 回答
0

大多数操作都是更新

所以你需要一个“真正的”合并。换句话说,您必须确定可以插入/更新数据的正确顺序,因此在此过程中不会违反 FK。

我不确定是什么parent_planet_id意思,但假设它的意思是“轨道”并且“行星”这个词被延伸到还包括卫星,假设你的主数据库中只有火卫一,火星和火卫二需要导入。这只能按特定顺序完成:

  1. 插入火星。
  2. INSERT Deimos,将其设置parent_planet_id为指向火星。
  3. 更新火卫一'parent_planet_id所以它指向火星。

虽然您可以交换步骤 (2) 和 (3),但您不能在步骤 (1) 之前进行任何操作。

您需要递归下降来确定正确的顺序,然后比较自然键1以查看需要更新的内容和插入的内容。不幸的是,MySQL 不支持递归查询,因此您需要手动进行。

我不太明白代理键在这个过程中有何帮助——如果有的话,它们会增加一个你最终必须协调的间接级别。


1与代理不同,它在不同的数据库中是有意义的。您不能只比较自动递增的整数,因为相同的整数值可能会识别不同数据库中的不同行星 - 您将获得错误的 UPDATE。另一方面,GUID 永远不会匹配,即使行描述的是同一个星球 - 你会有错误的 INSERT。

于 2012-09-17T15:31:51.560 回答