如何在SQL Server中批量迁移架构之间?


8

我们目前有多个数据库,但希望将它们组合起来,而是使用架构将我们的域上下文分开。

在MS SQL Server 2008 R2中,如何将一个架构的所有内容批量重新放置到另一个架构中?

例如,我们在dbo架构中创建的所有表,视图,过程,索引等... 现在都将存在于foo架构中。

编辑:我想根据AaronBertrand的精彩评论进行澄清。这不是多租户的情况。我们的情况是内部工具插件是由没有将表合并到工具数据库中的开发人员隔离开发的。


2
使用FK和其他依赖项可能会变得非常棘手。为什么要切换型号?我喜欢多DB模式在多模式模型各种各样的原因-见dba.stackexchange.com/questions/33550/...dba.stackexchange.com/questions/16745/...
阿龙贝特朗

@AaronBertrand的原因之一是,我们在单独数据库中的实体(例如,用户,在其自己的DB中)之间具有关系依赖性,而且,我们拥有跨越数据库的视图,因此无法使用架构绑定。
马修(Matthew)


您不需要外键来建立关系-可以用其他各种方式显式地强制执行这些关系。并且,除非对它们的视图进行索引,否则它们不需要SCHEMABINDING。我在这样的系统上工作了13年,可以向您保证,与将每个人合并到一个数据库中会丢失的东西相比,您担心的东西不值得担心。
亚伦·伯特兰

@AaronBertrand我的用例与您的链接中经常描述的用例之间的最大区别是,这些数据库不会以任何方式分隔客户端或租户。它们每个都由内部工具组合使用。它们分离的原因可能是因为开发人员在真空中创建了工具插件,然后将其附加而不合并到主数据库中。实际上,我们拥有单独的数据库来处理租约和不同的环境……
Matthew

Answers:


9

基本概念实际上非常简单:您可以从中生成脚本sys.objectssys.schemas构建ALTER SCHEMA TRANSFER语句。因此,例如,您在dbo架构中有三个对象,并且想要将它们全部移动到blat架构中:

Table: dbo.foo
Table: dbo.bar
View:  dbo.vFooBar

如下代码:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'
  ALTER SCHEMA blat TRANSFER dbo.' + QUOTENAME(o.name) + ';'
FROM sys.objects AS o
INNER JOIN sys.schemas AS s
ON o.[schema_id] = s.[schema_id]
WHERE s.name = N'dbo';

PRINT @sql;
-- EXEC sp_executesql @sql;

将产生以下脚本(但可能不按此顺序):

ALTER SCHEMA blat TRANSFER dbo.bar;
ALTER SCHEMA blat TRANSFER dbo.foo;
ALTER SCHEMA blat TRANSFER dbo.vFooBar;

(您可能需要添加额外的滤镜来离开了对象的dbo模式,你想要移动,离开了特定的对象类型(例如,也许您的所有功能都实用功能,并不需要移动),生成脚本按对象类型等排序)

但是,将您所有的对象移动到新架构中存在两个问题:

  1. 可能很多代码仍会引用这些对象,因为dbo.object-除蛮力外,没有简单的方法来解决此问题。您可能dbo.很容易找到所有出现的情况,但是这些情况也可能返回误报,例如EXEC dbo.sp_executesqldbo.中的注释,对保留在dbo.架构中的对象的真实引用等。

  2. 您的依赖关系可能会完全不合时宜,但我尚未对此进行全面测试。我确实知道在这种情况下:

    CREATE SCHEMA blat AUTHORIZATION dbo;
    GO
    
    CREATE TABLE dbo.foo(a INT PRIMARY KEY);
    CREATE TABLE dbo.bar(a INT FOREIGN KEY REFERENCES dbo.foo(a));
    GO
    
    CREATE PROCEDURE dbo.pX AS
    BEGIN
      SET NOCOUNT ON;
      SELECT a FROM dbo.bar;
    END
    GO
    
    CREATE VIEW dbo.vFooBar
    AS
      SELECT foo.a, bar.a AS barA
        FROM dbo.foo 
        INNER JOIN dbo.bar
        ON foo.a = bar.a;
    GO
    
    ALTER SCHEMA blat TRANSFER dbo.foo;
    ALTER SCHEMA blat TRANSFER dbo.bar;
    ALTER SCHEMA blat TRANSFER dbo.pX;
    ALTER SCHEMA blat TRANSFER dbo.vFooBar;

    实际上,外键迁移比我预期的要平稳得多(要注意的是,我正在比您测试的最新版本进行测试)。但是因为其中的代码blat.pX仍然引用dbo.bar,显然执行了该过程:

    EXEC blat.pX;

    将产生此错误:

    消息208,级别16,状态1,过程pX
    无效的对象名称'dbo.bar'。

    和依赖项查询,例如:

    SELECT * FROM sys.dm_sql_referenced_entities('blat.pX', N'OBJECT');

    将产生此错误:

    消息2020,级别16,状态1
    为实体“ blat.pX”报告的依赖项可能未包括对所有列的引用。这是因为该实体引用了一个不存在的对象,或者是由于该实体中的一个或多个语句中的错误。重新运行查询之前,请确保实体中没有错误,并且该实体引用的所有对象都存在。

    并查询视图:

    SELECT a, barA FROM blat.vFooBar;

    产生以下错误:

    消息208,级别16,状态1,过程vFooBar
    无效的对象名称“ dbo.foo”。
    消息4413,级别16,状态1
    由于绑定错误而无法使用视图或函数“ blat.vFoobar”。

    因此,这可能涉及大量清理工作。修复所有对象引用之后,您可能需要重新编译所有模块并刷新新模式中的所有视图。您可以为此生成一个脚本,该脚本与上面的示例非常相似。


+1,看来我需要手动删除一些 FK才能进行此传输...我不知道是什么原因造成的
Matthew

@Matthew是的,如果外键给您带来麻烦,请参阅此答案 -您只需对其进行调整,以便脚本的重新创建部分引用新的架构。
亚伦·伯特兰

@Matthew您是否知道存在什么情况会阻止某些带有外键的表顺利传输?您得到的确切错误消息是什么?知道您是否可以通过简单地禁用约束而不是放弃约束来绕过该约束……但由于我不知道您的确切阻止者是什么,我很难测试。
亚伦·伯特兰
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.