避免来自不同MySQL数据库的主键上的冲突

时间:2012-11-24 12:17:17

标签: php mysql doctrine doctrine-orm

我有几台服务器运行自己的特定MySQL数据库实例,遗憾的是无法在复制/集群中进行设置。每个服务器将数据插入到几个与用户相关的表中,这些表之间具有外键约束(例如useruser_vote)。以下是该过程的进展:

  1. 所有服务器都以相同的数据开头
  2. 每个服务器独立于其他服务器增加自己的数据集
  3. 定期将来自所有服务器的数据手动合并并应用回每个服务器(因此,流程将从步骤1开始重复)。
  4. 这是可能的,因为除了主键之外,user表还包含一个唯一的email字段,该字段允许识别每个数据库中已存在的用户,并合并新的用户。更改主键和外键以避免冲突并保持正确的外键约束。它可以工作,但这是一些努力,因为必须改变主键和外键以避免碰撞,因此我的问题是:

    有没有办法让每个服务器都使用不与其他服务器冲突的主键来促进合并?

    我最初想要使用复合主键(例如server_idid),但我使用的是Doctrine which doesn't support primary keys composed of multiple foreign keys,因此我的外键约束会出现问题。

    我考虑过使用VARCHAR作为id并使用部分字符串作为前缀(SERVER1-1,SERVER1-2,SERVER2-1,SERVER2-2 ......)但是我认为这将使DB变慢,因为我将不得不使用id进行一些操作(例如,在插入时,我必须解析现有的id并提取最高,增加它,将它与服务器id连接......)。

    PS:另一种选择是使用从从站的读取实现复制并写入主站,但由于主站上的复制滞后和单点故障等问题无法解决,因此该选项被丢弃现在

2 个答案:

答案 0 :(得分:2)

您可以确保每个服务器使用不同的自动增量增量和不同的起始偏移量:

Change the step auto_increment fields increment by

(假设您使用的是自动增量)

我只在两台服务器上使用过这个,所以我的设置有一个偶数id和一个奇数。

当它们合并在一起时,只要你确保所有表都遵循上述想法,就不会发生任何冲突。

以实现4台服务器

你会说,设置以下偏移量:

  • 服务器1 = 1
  • 服务器2 = 2
  • 服务器3 = 3
  • 服务器4 = 4

你可以设置你的增量(我用10来为额外的服务器留出空间):

  • 服务器1 = 10
  • 服务器2 = 10
  • 服务器3 = 10
  • 服务器4 = 10

然后在合并之后,在复制回每个服务器之前,您只需要更新每个表的autoinc值以再次获得正确的偏移量。想象一下,每个服务器创建了100行,autoincs将是:

  • 服务器1 = 1001
  • 服务器2 = 1002
  • 服务器3 = 1003
  • 服务器4 = 1004

由于有四台服务器,这就变得棘手了。想象一下,某些表可能没有从特定服务器插入任何行。所以你可能最终得到一些表,它们的最后一个autoinc id不是来自服务器4,而是来自服务器2。这将使得解决任何特定表的下一个autoinc应该是非常棘手的。

因此,最好在每个表中都包含一个列,用于在插入任何行时记录服务器编号。

id | field1 | field2 | ... | server

通过在任何表格中选择以下内容,您可以轻松找到特定服务器的最后一个autoinc值:

SELECT MAX(id) FROM `table` WHERE `server`=4 LIMIT 0,1

使用此值,您可以在将合并数据集滚动到相关服务器之前,重置每台服务器上每个表所需的下一个autoinc值。

UPDATE information_schema.tables SET Auto_increment = (
  SELECT MAX(id) FROM `table` WHERE `server`=s LIMIT 0,1
)+n WHERE table_name='table' AND table_schema = DATABASE();

其中s是服务器编号,n设置为偏移量,因此在我的示例中,它将是10

答案 1 :(得分:1)

前缀ID可以解决问题。至于DB速度较慢 - 取决于那里有多大的流量。您还可以将“前缀ID”分为两列,“前缀”和“id”,它们可以是任何类型。在请求中需要一些逻辑来处理它,但可能值得评估