¿Cómo migrar entre esquemas en masa en SQL Server?

8

Actualmente tenemos varias bases de datos, pero nos gustaría combinarlas y, en su lugar, separar nuestros contextos de dominio mediante esquemas.

En MS SQL Server 2008 R2, ¿cómo puedo reubicar todo el contenido de un esquema en otro de forma masiva?

Por ejemplo, todas las tablas, vistas, procedimientos, índices, etc. que creamos en el dboesquema ahora vivirán en el fooesquema.

EDITAR: Quería aclarar sobre la base de los excelentes comentarios de AaronBertrand. Esta no es una situación de arrendamiento múltiple. Nuestra situación es donde los complementos de herramientas internas fueron desarrollados de forma aislada por desarrolladores que no fusionaron sus tablas en la base de datos de la herramienta.

Mateo
fuente
2
Esto podría ser realmente complicado con FK y otras dependencias. ¿Por qué cambias de modelo? Me gusta el modelo multi-db sobre el modelo multi-esquema por una variedad de razones: consulte dba.stackexchange.com/questions/33550/… y dba.stackexchange.com/questions/16745/…
Aaron Bertrand
@AaronBertrand entre las razones es que tenemos dependencias relacionales entre entidades que están en bases de datos separadas (usuarios, por ejemplo, en su propia base de datos) y, además, que tenemos vistas que abarcan bases de datos y, por lo tanto, no podemos usar el enlace de esquemas.
Mateo
No necesita claves foráneas para tener relaciones; estas se pueden aplicar explícitamente de varias otras maneras. Y sus vistas no necesitan tener SCHEMABINDING a menos que estén indexadas. Trabajé con ese sistema durante 13 años, y puedo prometerle que no vale la pena preocuparse por las cosas que le preocupan en comparación con las cosas que perderá al combinar a todos en una sola base de datos.
Aaron Bertrand
@AaronBertrand la gran diferencia que veo entre mi caso de uso y el que a menudo se describe en su enlace es que estas bases de datos no separan a los clientes o inquilinos de ninguna manera. Cada uno de ellos es utilizado por una combinación de herramientas internas. Probablemente, la razón por la que están separados es porque el desarrollador crea el complemento de la herramienta en el vacío y luego lo adjunta sin fusionarse en la base de datos principal. En realidad vamos a tener separada de DB para hacer frente a entornos diferentes y tenencia ...
Mateo

Respuestas:

9

El concepto básico es realmente bastante simple: genera un script desde sys.objectsy sys.schemasque construye ALTER SCHEMA TRANSFERdeclaraciones. Entonces, por ejemplo, tiene tres objetos en el dboesquema y desea moverlos todos al blatesquema:

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

El siguiente código:

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;

Producirá este script (pero quizás no en este orden):

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

(Es posible que desee agregar filtros adicionales para omitir objetos en el dboesquema que no desea mover, omitir ciertos tipos de objetos (por ejemplo, tal vez todas sus funciones son funciones de utilidad y no necesitan moverse), generar el secuencia de comandos ordenada por tipo de objeto, etc.)

Pero hay un par de problemas al mover todos sus objetos a un nuevo esquema:

  1. Probablemente mucho su código seguirá haciendo referencia a estos objetos, ya que dbo.objectno hay una manera fácil de solucionarlo, excepto la fuerza bruta. Probablemente pueda encontrar todas las ocurrencias de manera dbo.bastante fácil, pero también pueden devolver falsos positivos, como EXEC dbo.sp_executesql, dbo.en los comentarios, referencias verdaderas a objetos que permanecen en el dbo.esquema, etc.

  2. Sus dependencias probablemente estarán completamente fuera de control, pero no lo he probado a fondo. Sé que en este escenario:

    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;
    

    Las claves externas en realidad migran más suavemente de lo que esperaba (con la advertencia que estoy probando en una versión mucho más reciente que usted). Pero debido a que el código blat.pXtodavía hace referencia dbo.bar, obviamente ejecuta el procedimiento:

    EXEC blat.pX;

    Va a producir este error:

    Mensaje 208, Nivel 16, Estado 1, Procedimiento pX
    Nombre de objeto no válido 'dbo.bar'.

    Y consultas de dependencia, como:

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

    Producirá este error:

    Mensaje 2020, Nivel 16, Estado 1
    Las dependencias informadas para la entidad "blat.pX" podrían no incluir referencias a todas las columnas. Esto se debe a que la entidad hace referencia a un objeto que no existe o debido a un error en una o más declaraciones de la entidad. Antes de volver a ejecutar la consulta, asegúrese de que no haya errores en la entidad y que existan todos los objetos a los que hace referencia la entidad.

    Y consultando la vista:

    SELECT a, barA FROM blat.vFooBar;

    Produce estos errores:

    Mensaje 208, Nivel 16, Estado 1, Procedimiento vFooBar
    Nombre de objeto no válido 'dbo.foo'.
    Msg 4413, Nivel 16, Estado 1
    No se pudo usar la vista o función 'blat.vFoobar' debido a errores de enlace.

    Entonces, esto podría implicar mucha limpieza. Y después de haber arreglado todas las referencias de objetos, probablemente querrá volver a compilar todos los módulos y actualizar todas las vistas en el nuevo esquema. Puede generar un script para eso bastante similar al ejemplo anterior.

Aaron Bertrand
fuente
+1, parece que necesito soltar manualmente algunos FK para hacer esta transferencia ... Todavía no sé qué causa eso
Matthew
@Matthew, sí, si las claves foráneas le causan problemas, vea esta respuesta : solo tendrá que ajustarla para que la parte de recreación del script haga referencia al nuevo esquema.
Aaron Bertrand
@Matthew, ¿ha descubierto qué circunstancia existe que impide que ciertas tablas con claves foráneas se transfieran sin problemas? ¿Cuál es el mensaje de error exacto que recibes? Sería interesante saber si puede evitar eso simplemente deshabilitando la restricción en lugar de soltarla ... pero es difícil para mí probarlo, ya que no sé cuál es su bloqueador exacto.
Aaron Bertrand