Wie migriere ich in SQL Server zwischen Schemas in großen Mengen?

8

Wir haben derzeit mehrere Datenbanken, möchten diese jedoch kombinieren und stattdessen unsere Domänenkontexte mithilfe von Schemas trennen.

Wie kann ich in MS SQL Server 2008 R2 den gesamten Inhalt eines Schemas in großen Mengen in ein anderes verschieben?

Beispielsweise werden alle Tabellen, Ansichten, Prozeduren, Indizes usw., die wir im dboSchema erstellt haben, jetzt im fooSchema gespeichert.

EDIT: Ich wollte anhand der großartigen Kommentare von AaronBertrand klarstellen. Dies ist keine Mandantenfähigkeitssituation. In unserer Situation wurden Plugins für interne Tools isoliert von Entwicklern entwickelt, die ihre Tabellen nicht in der Datenbank des Tools zusammengeführt haben.

Matthew
quelle
2
Dies könnte bei FK und anderen Abhängigkeiten sehr schwierig werden. Warum wechseln Sie Modelle? Ich mag das Multi- DB -Modell aus verschiedenen Gründen gegenüber dem Multi-Schema-Modell - siehe dba.stackexchange.com/questions/33550/… und dba.stackexchange.com/questions/16745/…
Aaron Bertrand
@AaronBertrand ist unter anderem der Grund dafür, dass wir relationale Abhängigkeiten zwischen Entitäten haben, die sich in separaten Datenbanken befinden (Benutzer beispielsweise in ihrer eigenen Datenbank), und dass wir Ansichten haben, die sich über Datenbanken erstrecken und daher keine Schemabindung verwenden können.
Matthew
Sie benötigen keine Fremdschlüssel, um Beziehungen zu haben - diese können auf verschiedene andere Arten explizit erzwungen werden. Und Ihre Ansichten müssen kein SCHEMABINDING haben, es sei denn, sie sind indiziert. Ich habe 13 Jahre lang mit einem solchen System gearbeitet, und ich kann Ihnen versprechen, dass die Dinge, über die Sie sich Sorgen machen, im Vergleich zu den Dingen, die Sie verlieren, wenn Sie alle in einer einzigen Datenbank zusammenfassen, keine Sorgen wert sind.
Aaron Bertrand
@AaronBertrand Der große Unterschied, den ich zwischen meinem Anwendungsfall und dem in Ihrem Link häufig beschriebenen sehe, besteht darin, dass diese Datenbanken Kunden oder Mandanten in keiner Weise trennen. Jeder von ihnen wird von einer Kombination interner Tools verwendet. Der Grund, warum sie getrennt sind, liegt wahrscheinlich darin, dass der Entwickler das Tool-Plugin in einem Vakuum erstellt und es dann anfügt, ohne es in die Hauptdatenbank zu integrieren. Wir tatsächlich wird verfügen über separate DB mit Miet- und unterschiedlichen Umgebungen zu behandeln ...
Matthew

Antworten:

9

Das Grundkonzept ist eigentlich recht einfach: Sie generieren ein Skript aus sys.objectsund sys.schemaserstellen ALTER SCHEMA TRANSFERAnweisungen. Sie haben beispielsweise drei Objekte im dboSchema und möchten alle in das blatSchema verschieben:

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

Der folgende Code:

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;

Wird dieses Skript ergeben (aber vielleicht nicht in dieser Reihenfolge):

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

(Möglicherweise möchten Sie zusätzliche Filter hinzufügen, um Objekte im dboSchema wegzulassen, die Sie nicht verschieben möchten, bestimmte Objekttypen weglassen (z. B. sind alle Ihre Funktionen Dienstprogrammfunktionen und müssen nicht verschoben werden) Skript sortiert nach Objekttyp usw.)

Es gibt jedoch einige Probleme beim Verschieben aller Ihrer Objekte in ein neues Schema:

  1. Wahrscheinlich verweist Ihr Code immer noch auf diese Objekte als dbo.object- es gibt keine einfache Möglichkeit, dies zu beheben, außer Brute Force. Sie können sich wahrscheinlich alle Vorkommen von finden dbo.ziemlich leicht, aber diese können auch falsch positive Ergebnisse , wie zurückkehren EXEC dbo.sp_executesql, dbo.in den Kommentaren, true Verweise auf Objekte , die in dem bleiben dbo.Schema usw.

  2. Ihre Abhängigkeiten werden wahrscheinlich völlig aus dem Ruder laufen, aber ich habe dies nicht gründlich getestet. Ich weiß das in diesem Szenario:

    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;
    

    Die Fremdschlüssel migrieren tatsächlich reibungsloser als erwartet (mit der Einschränkung, dass ich sie auf einer viel neueren Version als Sie teste). Aber weil der Code blat.pXimmer noch verweist dbo.bar, wird die Prozedur offensichtlich ausgeführt:

    EXEC blat.pX;

    Wird diesen Fehler ergeben:

    Meldung 208, Ebene 16,
    Status 1, Prozedur pX Ungültiger Objektname 'dbo.bar'.

    Und Abhängigkeitsabfragen wie:

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

    Wird diesen Fehler ergeben:

    Meldung 2020, Ebene 16,
    Status 1 Die für die Entität "blat.pX" gemeldeten Abhängigkeiten enthalten möglicherweise keine Verweise auf alle Spalten. Dies liegt entweder daran, dass die Entität auf ein nicht vorhandenes Objekt verweist, oder an einem Fehler in einer oder mehreren Anweisungen in der Entität. Stellen Sie vor dem erneuten Ausführen der Abfrage sicher, dass die Entität keine Fehler enthält und dass alle Objekte vorhanden sind, auf die die Entität verweist.

    Und die Ansicht abfragen:

    SELECT a, barA FROM blat.vFooBar;

    Ergibt diese Fehler:

    Meldung 208, Ebene 16, Status 1, Prozedur vFooBar
    Ungültiger Objektname 'dbo.foo'.
    Meldung 4413, Ebene 16,
    Status 1 Die Ansicht oder Funktion 'blat.vFoobar' konnte aufgrund von Bindungsfehlern nicht verwendet werden.

    Dies könnte also eine Menge Aufräumarbeiten beinhalten. Nachdem Sie alle Objektreferenzen korrigiert haben, möchten Sie wahrscheinlich alle Module neu kompilieren und alle Ansichten im neuen Schema aktualisieren. Sie können dafür ein Skript generieren, das dem obigen Beispiel sehr ähnlich ist.

Aaron Bertrand
quelle
+1, es scheint, als müsste ich einige FKs manuell fallen lassen , um diese Übertragung durchzuführen ... Ich weiß noch nicht, was das verursacht
Matthew
@Matthew Ja, wenn Ihnen Fremdschlüssel Probleme bereiten, lesen Sie diese Antwort. Sie müssen sie nur anpassen, damit der neu erstellte Teil des Skripts auf das neue Schema verweist.
Aaron Bertrand
@Matthew haben Sie herausgefunden, unter welchen Umständen bestimmte Tabellen mit Fremdschlüsseln nicht reibungslos übertragen werden können? Was ist die genaue Fehlermeldung, die Sie erhalten? Es wäre interessant zu wissen, ob Sie dies umgehen können, indem Sie die Einschränkung einfach deaktivieren, anstatt sie zu löschen ... aber für mich schwer zu testen, da ich nicht weiß, was Ihr genauer Blocker ist.
Aaron Bertrand