Das Projekt Database Shadow ist online

Bei einem aktuellen Kundenprojekt ist das kleine git hub Projekt Database Shadow entstanden. Der Name Database Shadow ist mir eingefallen, da man im Prinzip einen Schatten einer externen Datenbank im Schema einer anderen Datenbank erzeugt. Database Shadow besteht aus drei SQL Dateien die man sich bei git hub hier herunterladen kann.

Um zu erklären was genau Database Shadow macht muss ich ein bisschen ausholen. Bei der Datenbankprogrammierung in T-SQL ist ja so, dass man nicht nur Objekte in der eigenen Datenbank z.B. in Stored Procedures oder in Views referenzieren kann sondern man kann natürlich auch über einen dreiteiligen Namen auf eine andere Datenbank referenzieren. Beispiel:

SELECT * FROM database.schema.table;

Grundsätzlich ist eine solche Referenzierung auf Objekte in einer anderen Datenbank unschön. Wenn sich diese noch auf viele unterschiedliche Datenbank-Objekte verteilt wird es mit der Wartung des T-SQL Codes schwierig. Ändert sich die Datenbank auf die sich die Referenzen beziehen, dann muss man alle Stellen im Code herausfinden wo die Referenz auf das externe Objekt verwendet wurde und diese durch die neue Datenbank ersetzen. Gerade bei komplexen Datenbankprojekten ist das natürlich eine Mammut-Aufgabe.

Und genau hier kommt Database Shadow ins Spiel. Die Idee, die ich mal zusammen mit Torsten Strauß entwickelt habe ist die Folgende: Wie legen in der Datenbank in der es Referenzen auf Objekte in anderen Datenbanken gibt ein Schema an das genau wie die Datenbank heißt. In diesem Schema wird für jedes Objekt ein Synonym angelegt das genau so heißt wie das Objekt in der anderen Datenbank auf das es sich bezieht. Kleiner aber feiner Unterschied ist, dass Schema und Objektname durch einen Unterstrich voneinander getrennt werden. Einen Punkt können wir hier natürlich nicht verwenden, da wir beim Synonymnamen ja schon auf der untersten Namenshierarchiestufe angekommen sind. Mit dem Synonym würde unsere Beispiel oben wie folgt aussehen:

SELECT * FROM database.schema_table

Wenn wir nun in unserer Datenbank konsequent das Synonym an Stelle des vollqualifizierten Objektnamens in der anderen Datenbank verwenden gibt es im Fall einer Änderung der bezogenen Datenbank genau eine Stelle an der man etwas ändern muss – und zwar beim Synonym. Ändert man das Synonym so ab, dass es auf die neue Datenbank zeigt dann muss man am restlichen Code in der Datenbank nichts mehr ändern. Genau so gehe ich übrigens auch beim Test von Datenbanken mittelst tSQLt vor. Ich erzeuge eine eigene Test-Datenbank in der alle zu testenden Objekte per Synonym referenziert werden. Damit vermeide ich, dass ich mir die zu testende Datenbank mit tSQLt Code zumülle.

Grundsätzlich ist die Idee mit den Synonymen gut, hat aber den Nachteil, dass man diese erst einmal anlegen muss. Diese Aufgabe kann Database Shadow übernehmen. Die Stored Procedure database_shadow.create_shadow legt für alle Objekte in der bezogenen Datenbank dynamisch mit einem einzigen Aufruf alle Synonyme an. Hierbei wird natürlich auch ggf. das Schema mit dem Datenbanknamen angelegt. Die Prozedur ist idempotent, d.h. auch wenn ich sie schon einmal aufgerufen habe und von ihr angelegte Objekte in der Datenbank existieren führt ein weiterer Aufruf nicht dazu dass es einen Fehler gibt sondern es werden für alle Objekte die bisher nicht erfasst wurden Synonyme angelegt. Ein Beispielaufruf sieht dabei wie folgt aus:

EXEC database_shadow.create_shadow
      @pdatabase_name = 'meine_tolle_datenbank'
    , @pinclude_tables = 1
    , @pinclude_table_views = 0
    , @pinclude_procedures = 1
    , @pinclude_views = 1
    , @pinclude_scalar_functions = 1
    , @pinclude_table_valued_functions = 1
    , @pinclude_inline_table_valued_functions = 1
    , @pinclude_assembly_scalar_functions = 1
    , @pinclude_assembly_table_valued_functions = 1
    , @pinclude_sql_dml_trigger = 1
    , @pdebug = 0

Der einzige nicht-optionale Parameter ist @pdatabase_name. Hier muss man den Namen einer Datenbank auf demselben Server angeben. Alle anderen Parameter sind optional und stehen standardmäßig auf 1, d.h. das entsprechende Objekt wird erzeugt. Eine Besonderheit ist der Parameter @pinclude_table_views. Dieser Parameter ist dafür zuständig ob innerhalb des neu angelegten Datenbankschemas Views auf Basis der Tabellen-Synonyme angelegt werden sollen. Die Option hat folgenden Hintergrund: Mit tSQLt kann man in der aktuellen Version die Prozedure FakeTable nicht auf Tabellen anwenden die sich in einer anderen Datenbank befinden. Wenn man allerdings eine View erstellt die die Tabelle in der externen Datenbank abfragt und diese View mit FakeTable verwendet dann funktioniert es. Daher gibt es die Option @pinclude_table_views. Wenn tSQLt nicht eingesetzt werden soll kann man die Option getrost ausschalten.

Der letzte Parameter @pdebug ist für’s Debugging des dynamischen SQL Codes gedacht. Ist @pdebug auf 1, so werden die dynamisch erstellten T-SQL Befehle nicht ausgeführt sondern nur ausgegeben. Funktioniert etwas nicht kann man so nach der Ursache suchen.

Möchte man die „Schatten-Datenbank“ wieder loswerden kann man den Befehl database_shadow.drop_shadow verwenden. Diese Befehl löscht einfach das komplette Schema mit dem Namen der angegebenen Datenbank. Hier bitte vorsichtig sein und keine eigenen Objekte im Schema anlegen das create_shadow anlegt weil diese nach der Ausführung von drop_shadow natürlich auch weg sind.

EXEC database_shadow.drop_shadow  
   @pdatabase_name = 'meine_tolle_datenbank';

drop_shadow verfügt auch über einen @pdebug Parameter mit dem man sich den dynamisch generierten SQL Code ausgeben lassen kann. Ich hoffe da draußen gibt es außer mir noch Leute die Database Shadow gebrauchen können. Wenn Ihr Vorschläge für Erweiterungen oder Fehlermeldungen habt würde ich mich freuen wenn ihr diese in Git Hub als Issues einstellt.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

%d Bloggern gefällt das: