1

我有一个基于 Rails 3.2 多租户子域的应用程序,我正在尝试迁移到 PostgreSQL 的模式(每个帐户都有自己的模式——现在所有帐户都使用相同的表)。

所以,我想我需要:

  1. 创建一个新的数据库
  2. 为每个帐户(其 id)及其下的表创建一个模式
  3. 获取属于每个帐户的所有数据,并将其插入到该帐户架构下的新数据库中

这听起来正确吗?如果是这样,这样做的好方法是什么?我是否应该编写一个使用 ActiveRecord 的 ruby​​ 脚本,提取数据,然后将其插入(效率很低,但应该完成工作)到新数据库中?或者 Postgres 是否提供了很好的工具来做这样的事情?

编辑:

正如 Craig 建议的那样,我在现有数据库中创建了模式。然后,我在 Rake 任务中遍历所有帐户,并使用以下内容复制数据:

Account.all.each do |account|

  PgTools.set_search_path account.id, false
  sql = %{INSERT INTO tags SELECT DISTINCT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."tagger_id" = #{admin.id} AND "taggings"."tagger_type" = 'User'}
  ActiveRecord::Base.connection.execute sql

  #more such commands

end
4

1 回答 1

3

我会亲自使用 SQL 进行转换。

在与当前数据库相同的数据库中创建新模式以便于迁移,因为您无法使用 PostgreSQL 轻松跨数据库查询。

INSERT INTO ... SELECT使用适当的查询迁移数据。要做到这一点而不必禁用任何外键,您应该构建数据的依赖关系图。首先将数据复制到不依赖于任何内容的表中,然后复制到依赖于它们的表中,依此类推。

您需要为每个客户模式重复此操作,因此请考虑创建一个使用EXECUTE ...动态 SQL 的 PL/PgSQL 函数来:

  • 为客户创建架构
  • 在架构中创建表
  • 通过循环硬编码的表名数组以正确的顺序复制数据,执行以下操作:

    EXECUTE `'INSERT INTO '||quote_ident(newschema)||'.'||quote_ident(tablename)||' SELECT * FROM oldschema.'||quote_ident(tablename)||' WHERE customer_id = '||quote_literal(customer_id)'||;'
    

    其中newschema和是 PL tablename/ customer_idPgSQL 变量。

然后,您可以从 SQL 调用该函数。虽然您可以这样做select convert_customer(c.id) FROM customer GROUP BY c.id,但我可能会从外部控制脚本中进行,这样每个客户的工作都可以单独完成并提交,如果倒数第二个客户转换失败,则无需从头开始。

对于额外的疯狂点,甚至可以在主要客户模式的表上定义触发器,将更改复制到已经迁移的客户到新模式中的数据副本,这样他们就可以在迁移期间继续使用系统。我会避免这种情况,除非迁移太大而无法在没有停机的情况下进行,因为测试将是一场噩梦,并且您仍然需要触发器在迁移时通过客户 id x引发错误x ' s 数据实际上正在进行中,因此它不会完全透明。

如果您为不同的客户使用不同的登录用户(强烈推荐),您的功能还可以:

  • REVOKE架构上的权限来自public
  • GRANT将使用它的用户或角色对架构的有限权限
  • REVOKE对创建的每个表的公共权限
  • GRANT用户和角色对每个表的期望有限权限
  • GRANT在这些表使用的任何序列上。即使序列是由SERIAL伪列创建的,这也是必需的。

这样,您的所有权限都是一致的,您以后不需要去更改它们。请记住,您的 webapp永远不应以超级用户身份登录。

于 2012-08-07T23:33:15.870 回答