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

Mat*_*hew 8 schema sql-server-2008-r2

我们目前有多个数据库,但希望将它们组合起来,取而代之的是使用模式分离我们的域上下文。

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

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

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

Aar*_*and 9

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

Table: dbo.foo
Table: dbo.bar
View:  dbo.vFooBar
Run Code Online (Sandbox Code Playgroud)

以下代码:

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;
Run Code Online (Sandbox Code Playgroud)

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

ALTER SCHEMA blat TRANSFER dbo.bar;
ALTER SCHEMA blat TRANSFER dbo.foo;
ALTER SCHEMA blat TRANSFER dbo.vFooBar;
Run Code Online (Sandbox Code Playgroud)

(您可能需要添加额外的滤镜来离开了对象的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;
    
    Run Code Online (Sandbox Code Playgroud)

    外键的迁移实际上比我预期的更顺利(需要注意的是,我正在测试比您更新的版本)。但是因为里面的代码blat.pX还是引用了dbo.bar,显然是在执行这个过程:

    EXEC blat.pX;
    
    Run Code Online (Sandbox Code Playgroud)

    将产生此错误:

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

    以及依赖查询,例如:

    SELECT * FROM sys.dm_sql_referenced_entities('blat.pX', N'OBJECT');
    
    Run Code Online (Sandbox Code Playgroud)

    会产生这个错误:

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

    并查询视图:

    SELECT a, barA FROM blat.vFooBar;
    
    Run Code Online (Sandbox Code Playgroud)

    产生这些错误:

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

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