Postgres:重组为架构

时间:2012-08-07 08:12:10

标签: ruby-on-rails-3 postgresql activerecord multi-tenant

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

所以,我想我需要:

  1. 创建新数据库
  2. 为每个帐户(其ID)及其下的表格
  3. 创建架构
  4. 抓取属于每个帐户的所有数据,并将其插入到所述帐户架构下的新数据库中
  5. 这听起来不对吗?如果是这样,那么这样做的好方法是什么?我应该编写一个使用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
    

1 个答案:

答案 0 :(得分: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)'||;'
    

    其中newschematablenamecustomer_id是PL / PgSQL变量。

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

对于奖励疯狂点,甚至可以在主要客户架构的表上定义触发器,这些触发器将已迁移客户的更改复制到新架构中的数据副本,以便他们可以在迁移期间继续使用系统。我会避免这种情况,除非迁移太大而没有停机时间,因为测试是一个噩梦,你仍然需要触发器来引发客户ID x 虽然 x 的数据迁移实际上正在进行中,因此它不会完全透明。

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

    来自REVOKE 的架构的
  • public权利
  • GRANT模式对用户或角色的有限权利
  • REVOKE来自每个创建的表的公开权
  • GRANT每个表对用户和角色的所需有限权利
  • GRANT关于这些表使用的任何序列。即使序列是由SERIAL伪列创建的,也需要这样做。

这样,您的所有权限都是一致的,您无需在以后更改它们。请记住,您的网络应用从不以超级用户身份登录。