Come migrare tra schemi in blocco in SQL Server?


8

Al momento disponiamo di più database ma vorremmo combinarli e, invece, separare i nostri contesti di dominio usando schemi.

In MS SQL Server 2008 R2, come posso trasferire tutti i contenuti di uno schema in un altro in blocco?

Ad esempio, tutte le tabelle, viste, procedure, indici, ecc ... che abbiamo creato nello dboschema ora vivranno nello fooschema.

EDIT: volevo chiarire sulla base dei grandi commenti di AaronBertrand. Questa non è una situazione multi-tenancy. La nostra situazione è quella in cui i plug-in degli strumenti interni sono stati sviluppati separatamente dagli sviluppatori che non hanno unito le loro tabelle nel database dello strumento.


2
Questo potrebbe diventare davvero complicato con FK e altre dipendenze. Perché stai cambiando modello? Mi piace il modello multi-db rispetto al modello multi-schema per una serie di motivi - vedi dba.stackexchange.com/questions/33550/… e dba.stackexchange.com/questions/16745/…
Aaron Bertrand

@AaronBertrand tra i motivi è che abbiamo dipendenze relazionali tra entità che si trovano in database separati (utenti, ad esempio, nel proprio DB) e, inoltre, che abbiamo viste che abbracciano database e quindi non possiamo usare schemi di associazione.
Matteo,


Non hai bisogno di chiavi esterne per avere relazioni, queste possono essere applicate esplicitamente in vari altri modi. E le tue viste non devono avere SCHEMABINDING a meno che non siano indicizzate. Ho lavorato con un tale sistema per 13 anni e posso prometterti che le cose di cui ti preoccupi non valgono la pena rispetto alle cose che perderai combinando tutti in un unico database.
Aaron Bertrand

@AaronBertrand la grande differenza che vedo tra il mio caso d'uso e quella spesso descritta nel tuo link è che questi database non separano client o tenant in alcun modo. Ognuno di essi è utilizzato da una combinazione di strumenti interni. Probabilmente il motivo per cui sono separati è perché lo sviluppatore crea il plug-in dello strumento nel vuoto, quindi lo collega senza unirsi al DB principale. In realtà avremo DB separati per occuparci della locazione e di ambienti diversi ...
Matteo,

Risposte:


9

Il concetto di base è in realtà abbastanza semplice: si genera uno script da sys.objectse sys.schemasche crea ALTER SCHEMA TRANSFERdichiarazioni. Quindi, ad esempio, hai tre oggetti nello dboschema e vuoi spostarli tutti nello blatschema:

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

Il seguente codice:

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;

Produrrà questo script (ma forse non in questo ordine):

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

(Potresti voler aggiungere filtri aggiuntivi per escludere oggetti nello dboschema che non desideri spostare, escludere determinati tipi di oggetti (ad esempio, forse tutte le tue funzioni sono funzioni di utilità e non è necessario spostare), genera il script ordinato per tipo di oggetto, ecc.)

Ma ci sono un paio di problemi con lo spostamento di tutti i tuoi oggetti in un nuovo schema:

  1. Probabilmente molto il tuo codice farà comunque riferimento a questi oggetti come dbo.object- non esiste un modo semplice per risolvere questo, tranne la forza bruta. Probabilmente si può trovare tutte le occorrenze di dbo.abbastanza facilmente, ma questi possono anche restituire falsi positivi, come ad esempio EXEC dbo.sp_executesql, dbo.nei commenti, veri riferimenti a oggetti che rimangono in dbo.schema, ecc

  2. Le tue dipendenze probabilmente saranno completamente fuori di testa, ma non l'ho testato a fondo. So che in questo scenario:

    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;
    

    Le chiavi esterne in realtà migrano più agevolmente di quanto mi aspettassi (con l'avvertenza che sto testando su una versione molto più recente di te). Ma poiché il codice fa blat.pXancora riferimento dbo.bar, ovviamente eseguendo la procedura:

    EXEC blat.pX;

    Produrrà questo errore:

    Messaggio 208, livello 16, stato 1, procedura pX
    Nome oggetto non valido 'dbo.bar'.

    E domande di dipendenza, come:

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

    Produrrà questo errore:

    Messaggio 2020, livello 16, stato 1
    Le dipendenze riportate per l'entità "blat.pX" potrebbero non includere riferimenti a tutte le colonne. Ciò è dovuto al fatto che l'entità fa riferimento a un oggetto che non esiste o a causa di un errore in una o più istruzioni nell'entità. Prima di rieseguire la query, assicurarsi che non vi siano errori nell'entità e che esistano tutti gli oggetti a cui fa riferimento l'entità.

    E interrogare la vista:

    SELECT a, barA FROM blat.vFooBar;

    Produce questi errori:

    Messaggio 208, livello 16, stato 1, procedura vFooBar
    Nome oggetto non valido 'dbo.foo'.
    Messaggio 4413, livello 16, stato 1
    Impossibile utilizzare la vista o la funzione "blat.vFoobar" a causa di errori di associazione.

    Quindi, ciò potrebbe comportare molta pulizia. E dopo aver corretto tutti i riferimenti agli oggetti, probabilmente vorrai ricompilare tutti i moduli e aggiornare tutte le viste nel nuovo schema. Puoi generare uno script abbastanza simile all'esempio sopra.


+1, mi sembra di dover eliminare manualmente alcuni FK per eseguire questo trasferimento ... Non so ancora cosa lo causi
Matthew,

@Matthew sì, se le chiavi esterne ti danno problemi, vedi questa risposta - dovrai solo regolarla in modo che la parte ricreata dello script faccia riferimento al nuovo schema.
Aaron Bertrand

@Matthew hai capito quali sono le circostanze che impediscono il trasferimento regolare di alcune tabelle con chiavi esterne? Qual è il messaggio di errore esatto che ricevi? Sarebbe interessante sapere se puoi aggirarlo semplicemente disabilitando il vincolo invece di lasciarlo cadere ... ma è difficile per me testarlo poiché non so quale sia il tuo esatto blocco.
Aaron Bertrand
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.