如何设计模式来处理定期批量插入/更新?

时间:2012-09-17 09:07:07

标签: mysql database-design import amazon-web-services

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

我有一个带有像 planets 这样的表的生产数据库,虽然它具有很好的潜在自然键(例如,从未真正改变的行星名称),但使用典型的递增整数作为主键。行星表有一个或两个自引用列,例如* parent_planet_id *。

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

  • 工作者实例具有数据库的迷你版本(相同的架构,但没有行星记录)
  • 每周一次,工人开火,完成所有处理,创建10万左右的行星记录,然后输出数据。 (我不认为导出格式对这个特殊问题很重要:可能是mysqldump,yaml等。)
  • 然后,生产服务器导入记录:一些是新记录,大多数是更新。

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

我考虑过没有id列的导出,但后来我意识到自引用列阻止了这一点。

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

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

3 个答案:

答案 0 :(得分:1)

修改Planets以使用替代层次结构技术,例如 nested sets 关闭表路径枚举而不是出口。这将打破ID依赖。

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

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

在任何情况下,来自第一个数据库的代理键都不应该离开该数据库 - 它没有任何意义。

答案 1 :(得分:0)

最佳解决方案(就设计而言)将是改进您的密钥架构并实现一些复合密钥,其中包含有关导入行星的时间和地点的信息,但您不希望这样做。

更容易(我认为),但有点“快乐的工程”解决方案是修改导入密钥。你可以这样做,例如: 1.锁定主系统中的行星表(因此在导入过程中不会出现新的键), 2.创建具有两列的查找表,基于主系统中行星表的ID和PLANET NAME, 3.从该表中获取最大键值, 4.通过添加在步骤#3中重新获得的MAX值,递增每个导入的密钥(识别和引用父子行星关系)值, 5.更改主星球表并更改当前自动增量值以获得实际MAX + 1值 6.现在查看表(过程中的光标循环),检查当前行星名称是否在查找中有不同的键,如果是,则首先从查找中删除表中的记录(旧的)并更新当前检查的行中用于旧ID的密钥值(即更新), 7.打开桌子。

答案 2 :(得分:0)

  

大多数操作都是更新

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

我不确定parent_planet_id是什么意思,但假设它意味着“轨道”而“行星”这个词也被拉伸以包含卫星,想象一下你的主数据库中只有火球,火星和Deimos需要进口。这只能按特定顺序进行:

  1. INSERT Mars。
  2. INSERT Deimos,将其parent_planet_id设置为指向火星。
  3. 更新Phobos'parent_planet_id所以它指向火星。
  4. 虽然您可以交换步骤(2)和(3),但在步骤(1)之前无法做到。

    您需要递归下降来确定正确的顺序,然后比较自然键 1 以查看需要UPDATEd和INSERTed的内容。不幸的是,MySQL不支持递归查询,所以你需要手动完成。

    我不太清楚代理键如何在这个过程中起作用 - 如果有的话,它们会增加一个你最终需要协调的间接层。


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