Snowflake-Schema-Dimensionen mit NULL-Values konfigurieren

Eine Möglichkeit, eine Dimension relational abzubilden, ist ein Snowflake-Schema. In diesem Schema werden Hierarchien so abgebildet, dass jede Hierarchiestufe eine eigene Tabelle besitzt, die durch Foreign Keys verbunden sind.

Probleme können auftreten, wenn nicht bei allen Dimensionselementen alle Ebenen vorhanden sind und deshalb manche Elemente in der Datenbank NULL sind. Diese können über das Setzen der Eigenschaft „NULL Processing“ gelöst werden. Fangen wir aber vorne an.

Ein Beispiel für eine Dimension im Snowflake-Schema seien die Hierarchien Produkt > Warengruppe > Strategisches Geschäftsfeld (SGF) und Produkt > Produktionskennzeichen (hier ein Screenshot des Data Source View):

Data Source View Produkt Dimension

Daraus lässt sich einfach eine Dimension bauen:

Dimension Produkt mit Hierarchien
(Zum Vergrößern Bild anklicken)

Die einzelnen Attribute sind so definiert: Die Key-Column ist jeweils die ID-Spalte (also zum Beispiel id aus der Tabelle dim_SGF), die Name-Column jeweils die zugehörige Bezeichnung (z.B. die Tabelle SGFBezeichnung der Tabelle dim_SGF).

In meinem Beispiel kann die Produktionskennzeichen_ID der dim_Produkt NULL sein.

Das hätte jetzt zur Folge, dass – Stand jetzt – die Dimension nicht aufbereitet werden kann:

Fehler beim aufbereiten der Dimension
(Zum Vergrößern Bild anklicken)

Die Fehlermeldung im Detail:

Fehler im OLAP-Speichermodul: Der Attributschlüssel wurde bei der Verarbeitung nicht gefunden: Tabelle: dbo_dim_Produktionskennzeichen, Spalte: id, Wert: 0. Das Attribut ist ‚Produktionskennzeichen‘. Fehler im OLAP-Speichermodul: Fehler beim Verarbeiten des Produkt-Attributs der Produkt-Dimension aus der SimpleCube-Datenbank.

Offensichtlich hat der SSAS den NULL-Wert als 0 interpretiert, was er natürlich nicht finden kann.

Die Lösung ist:

  • Definieren des Unknown-Members der Dimension als sichtbar mit der Bezeichnung „unbekannt“ (oder wie auch immer)
  • Definieren der Nullprocessing-Eigenschaft der Key Column von Produktionskennzeichen auf „ConvertToUnknown“:
    Null Processing bei der Key Coulmn eines Attributs

Dann funktioniert die Aufbereitung und die Dimensionen sehen in meinem Beispiel so aus (die Zahlen sind irgendwelche Artikelnummern 🙂 ):

Hierarchie SGF:
Hierarchie SGF

Hierarchie Produktionskennzeichen:
Hierarchie Produktionskennzeichen

SSRS: Darstellung von multi-valued Parametern im Report

In Berichten ist es eine gute Angewohnheit, die durch den Benutzer ausgewählten Parameter im Bericht anzuzeigen.

Bei Parametern, die dem Benutzer nur einen Wert einzugeben, ist das einfach, da dieser Ausdruck im Ausdruck-Editor einfach zusammengeklickt werden kann, zu z.B.

=“Eingegebene Zahl: “ & Parameters!EinfacherParam.Value

Parameter mit einem Wert

(Zum Vergrößern aufs Bild klicken)

Wenn es sich aber um einen Multi-Value Parameter (wie in meinem Beispiel der Parameter „Wochentag“) handelt, dann erzeugt der Ausdruck-Editor … Parameters!Wochentag.Value(0), was den Value (das ist der Schlüssel) ersten ausgewählten Wochentag ausgibt.

Da mir aber etwas wie „Sie haben folgende Wochentage ausgewähtl: Montag, Dienstag, …“ vorschwebt, müssen wir zunächst den Label anzeigen lassen und nicht den Schlüssel. Das geht über Parameters!Wochentag.Label(0).

Nun wollen wir aber alle ausgewählten Parameterwerte sehen und nicht nur den ersten. Da es sich bei Parameters!Wochentag.Label offensichtlich um ein Array handelt (Array startet mit Position 0), kann man über die Join-Funktion die einzelnen Werte konkatenieren.

Dazu kann man folgenden Code im Ausdruck-Fenster eingeben:

=“Alle (via Ausdruck): “ &
Join(Parameters!Wochentag.Label, „, „)

Alle Params via Ausdruck

Damit endet die Möglichkeit im Ausdruck-Fenster.

Will man weitere Funktionalität einbauen, wie z.B. die Liste 1-Montag, 2-Dienstag, …, so kann man das dadurch erreichen, dass man im Code-Fenster auf die Parameter und ihre Werte zugreifen kann:

Code eingeben

(Zum Vergößern Bild anklicken)

Das Code-Fenster erreicht man über Bericht > Berichsteigenschaften > Code.

Dort habe ich folgenden Code eingefügt:

function ParameterwerteVerkettet(ParamName as string)
dim i as integer
dim erg as string

for i = 1 to Report.Parameters(ParamName).Count
erg = erg & Report.Parameters(ParamName).Value(i-1) & „: „
erg = erg & Report.Parameters(ParamName).Label(i-1)
if i<> Report.Parameters(ParamName).Count Then erg = erg & „; „
next i

ParameterwerteVerkettet=erg
end function

Wie man sieht, kann man einfach in dem VB-Code auf die Parameter-Arrays Value und Label zugreifen.

Diese Funktion ruft man dann im Ausdruck wie folgt auf:

Ausdruck via Code

Mein fertiger Bericht sieht dann wie folgt aus:

fertiger Report

Das RDL kann man hier runterladen: www.csopro.de/blogdateien/ParamsAnzeigen.rdl

Noch einige weiterführende Hinweise:

Nachinstallieren von Visual Studio 2008 Komponenten schlägt fehl

Bei einem Kunden mussten DLLs in VB.NET und nicht C# erstellt werden, weswegen ich bei meiner Visual Studio Installation VB.NET hinzufügen wollte.

Leider scheiterte das, sowohl über Systemsteuerung > Software > Visual Studio 2008 > Ändern als auch beim Starten von der Visual Studio DVD.

Jeweils scheiterte bereits das Hochfahren der Setup-Komponente.

Am Anfang werden ja etliche Sachen in der Setup-Komponente geladen und getestet und mitten dabei brach das Setup ab, so dass ich nicht einmal zur Auswahl der Komponenten gelangte.

Glücklicherweise fand ich den Link http://blogs.msdn.com/heaths/archive/2008/10/06/adding-features-to-visual-studio-2008-may-fail-to-load-setup-components.aspx, der genau dieses Problem beschreibt.

Man kann entweder alle Patches von Visual Studio 2008 entfernen oder am besten Visual Studio 2008 Service Pack 1 installieren.

Migration SSAS 2005 > 2008: Class not registered – Fehler

Wenn man eine SSAS-Datenbank von SQL 2005 auf SQL Server Analysis Services 2008 migriert, taucht gerne folgender Fehler auf, der aber eine nicht auf Anhieb durchschaubare Fehlermeldung hat:

Die Migration geht an sich gut. Hat man die SSAS-Datenbank dann aber auf den neuen Server mit SSAS 2008 deployt, so bereitet die Datenbank nicht auf, sondern scheitert mit folgendem Fehler:

Class not registered beim Aufbereiten
(Zum Vergrößern auf das Bild klicken)

Der Fehler tritt nur auf, wenn die Daten auf dem SQL Server liegen und nach der Migration auf dem Zielserver keine SQL Server 2005-Installation mehr vorhanden ist.

Ursache ist, dass in der Data Source als OLEDB Treiber der SQL Server Native Client in der Version 2005 angegeben ist, aber auf dem neuen Zielserver nicht mehr installiert ist.

Alte Verbindung mit 2005er Treiber

Man kann einfach den Treiber auf die aktuelle Version 2008 (10.0) ändern. Dann funktioniert wieder alles (egal ob die zugrundeliegende Datenbank noch SQL Server 2005 ist oder auch auf SQL 2008 migriert wurde):

Verwendung des neuen Treibers von SQL 2008

Verhalten von Views bei Strukturänderungen der zugrundeliegenden Tabellen

Ein View, der mittels * alle Spalten einer verwendeten Tabelle zurückgibt, wie z.B.

CREATE VIEW dbo.testView
AS
SELECT u.*, k.name as Kunden_Name, k.AnzahlKinder
FROM umsatz u
INNER JOIN kunde k
ON k.kunde_id = u.kunde_id

verhält sich überaschend, wenn sich die Tabellenstruktur der zugrunde liegenden Tabellen ändert. Die Metainformationen aktualisieren sich nämlich nicht automatisch, was sogar zu Datentypsverletzungen führen kann.

Nehmen wir an, die Tabelle umsatz aus obigen Beispiel habe folgenden Inhalt:

Inhalt der Tabelle Umsatz

Damit liefert die Abfrage des Views

SELECT * FROM testView

folgende Daten:

Inhalt des TestView original

Wird nun in der Tabelle umsatz eine Spalte Rabatt hinzugefügt (und mit Werten gefüllt), liefert das SELECT überaschender Weise:

nach Hinzunahme der Spalte Inhalt des Views

Dabei fällt auf, dass die Spaltentitel die ursprünglichen Inhalte haben, d.h. Rabatt ist nirgends zu sehen, die Werte der Spalten sind aber falsch: In der Spalte Kundenname steht nun der Rabatt und im Feld AnzahlKinder (Datentyp ist eigentlich int!) steht nun der Kundenname.

Das Aktualisieren der Views geht einfach: Nach

exec sp_refreshview 'testview'

sieht wieder alles richtig aus.

Hat man mehrere Views, in einer Datenbank, kann man über

select 'exec sp_refreshview ''' + name + '''' from sysobjects
where xtype = 'V'

sich die notwendigen SQL-Statements automatisch generieren lassen, die man dann einfach ausführt.

Einige Hinweise:

  • Views können natürlich verschachtelt sein, d.h. ein View greift auf einen anderen View zu. Dann müssen die Refresh-View-Statements in der richtigen Reihenfolge oder einfach mehrfach ausgeführt werden.
  • Clustered / Indexed Views können nicht refresht werden – das Statement liefert einen Fehler und muss aus der Liste der auszuführenden Statements gelöscht werden. Das Aktualisieren eines indizierten Views ist aber auch unnötig, da die zugrunde liegenden Tabellen nicht geändert werden können (da der View mit Schema Binding angelegt wurde)

Kalendersteuerelement bei Reports auf Cubes

Reporting Services hat ein Kalendersteuerelement, in dem man Datumswerte einfach eingeben kann, wenn ein Prompt vom Typ Date / Time ist. Heute möchte ich beschreiben, wie man das verwenden kann, wenn man einen Bericht erstellt, der auf einem Analysis Services-Cube basiert. Beim Cube ist (in der Regel) das Problem, dass es zwar eine Zeit-Dimension gibt, diese aber natürlich wie alle Dimensionen einen Member Unique Name (also Key) wie z.B. „[Intervall].[Datum].&[20081012]“ oder „[Intervall].[Datum].&[3207]“ haben. Dies ist offensichtlich ein String und kein DateTime, weswegen beim Standard-Vorgehen der Reporting Services eine Kombobox mit allen Datumswerten erstellt.

Aber hier im Detail das Vorgehen:

Im Wizard zum Erstellen der Abfrage gehen wir wie folgt vor:

Wizard zum Erstellen der Abfrage an den Cube

(Zum Vergrößern auf das Bild klicken)

Ich habe einfach eine Kennzahl und das Datum in die Abfrage gezogen und einen Filter auf das Datum gesetzt, wobei ich (wichtig!) die beiden Checkboxen bei den Parametern gesetzt habe.

Bei der Berichtsausführung werden die beiden Parameter über Komboboxen realisiert:

Parameter From als Kombobox

Dazu hat nämlich der Wizard zwei versteckte Data Sets angelegt, die die entsprechenden Werte liefern:

Hidden Datasets

Als nächstes müssen wir das MDX anpassen. (Im Query Designer auf Design Mode klicken)

 

Der Wizard hat folgendes MDX erstellt:

SELECT NON EMPTY { [Measures].[Annahmen] } ON COLUMNS, NON EMPTY { ([Intervall].[Datum].[Datum].ALLMEMBERS ) } DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME ON ROWS FROM ( SELECT ( STRTOMEMBER(@FromIntervallDatum, CONSTRAINED) : STRTOMEMBER(@ToIntervallDatum, CONSTRAINED) ) ON COLUMNS FROM [<CubeName>]) CELL PROPERTIES VALUE, BACK_COLOR, FORE_COLOR, FORMATTED_VALUE, FORMAT_STRING, FONT_NAME, FONT_SIZE, FONT_FLAGS

Die beiden mit @-benannten Ausdrücke sind die Prompts.

Wir müssen nun den Teil „STRTOMEMBER(@FromIntervallDatum, CONSTRAINED) “ so abändern, dass dort eine Variable vom Typ DateTime eine Rolle spielt. Der Schlüssel eines Datumselements in diesem Fall sieht so aus „[Intervall].[Datum].&[3190]“, wobei die ID die Anzahl der Tage zwischen dem 1.1.2000 und dem betreffenden Tag ist.

Gehen wir nun davon aus, dass wir einen Prompt @von vom Typ DateTime haben, müsste der STRTOMEMBER so aussehen:

STRTOMEMBER(„[Intervall].[Datum].&[“ +cstr( datediff(„d“, DateSerial(2000, 1, 1), @von )) + „]“)

Die DateSerial-Funktion verwende ich hier aus hygienischen Gründen, um keinen Cast von String auf DateTime (der abhängig von der Locale wäre) zu verwenden)

Auf das CONSTRAINED verwende ich, da sonst der Query Designer meckert.

Wenn man selbst natürlich einen anderen Key benutzt, muss dies angepasst werden. Bei einem Key im Format YYYYMMDD, also [Intervall].[Datum].&[20091205], müsste die Formel so sein:

STRTOMEMBER(„[Intervall].[Datum].&[“ +cstr( year(@von) ) + right(„0“ + cstr(month(@von), 2) + right(„0“ + cstr(day(@von), 2) + „]“)

Nun müssen wir noch den Parameter der Abfrage definieren (über Button Abfrage Parameter):

Parameter der Abfrage

Damit existiert noch nicht der Prompt.

Unter den Eigenschaften des Datasets erscheint der Parameter @von bereits:

Dataset Properties: Parameter

Dort tragen wir in „Parameter Value“ einfach „[@von]“ ein.

Damit wird automatisch ein Report Parameter von angelegt

Report Parameter von, den wir wie folgt bearbeiten: Wir setzen den Datentyp auf Datetime:

Bild

(Außerdem löschen wir den nicht mehr benötigten Prompt „FromIntervallDatum“)

Damit steht jetzt auch hier das Kalendersteuerelement zur Verfügung:

fertiges Kalendersteuerelement

Unerwartetes Nicht-Logging SSIS

Dieser Artikel widmet sich nicht dem Logging, das man selbst in einem Paket aktivieren kann und über Log-Provider detailliert steuern kann.

Gemeint ist mehr das Logging, das SSIS automatisch ohne Zutun des Entwicklers oder Administrators durchführt, s. dazu auch „Understanding Events Logged by an Integration Services Package„.

Standardmäßig loggt jedes SSIS-Paket den Start, das erfolgreiche Ende oder das Fehlschlagen oder Abbrechen eines SSIS-Pakets:

EventLog Start und Failure eines SSIS Pakets

(Zum Vergößern auf das Bild klicken)

Details des Eventlogs beim Scheitern eines Pakets

(Randbemerkung: Das Logging von Start und erfolgreichem Ende lässt sich abschalten – in der Registry HKEY_LOCAL_MACHINESOFTWAREMicrosoftMicrosoft SQL Server100SSIS, Wert von „LogPackageExecutionToEventLog“ auf 1 setzen – die anderen Einträge lassen sich nicht verhindern)

In dem Beispiel hatte ich ein SSIS-Paket erstellt, das nur aus einer Script-Task bestand, die immer einen Fehler schmeißt:

Script-Task zum Fehler schmeißen

Dort ist folgender Code enthalten:

public void Main()
{
Dts.Events.FireError(999, „SubKomponente A“, „Fehler – Test fehler“, „“, 0);
Dts.TaskResult = (int)ScriptResults.Success;
}

Das Ergebnis ist oben zu bewundern.

Nun hatten wir die Idee, dieses Eintrag im Event Log zu überwachen (mit NetIQ oder einem anderen Werkzeug zur Überwachung von Servern, Diensten, etc.) und so zu erfahren, wenn ein Paket gescheitert ist.

Das funktioniert aber leider nicht.

Der Grund ist, dass ein solcher Eintrag im Eventlog nur erzeugt wird, wenn das Paket bereits angelaufen ist. Wenn aber schon bei der Validierung ein Fehler auftritt, wird kein Eintrag im Eventlog erzeugt.

Dazu habe ich das Paket erweitert um einen Data Flow Task, bei dem ich in der Quelle „SELECT 1 as Zahl“ eingetragen habe. SSIS Paket mit Fehler brerits beim Validieren

Dieses Paket habe ich dann im SQL Server Agent als Job eingerichtet. Dabei habe ich eingestellt, dass im Fehlerfall der SQL Server Agent das Ergebnis im Eventlog festhalten soll:

Properties des SQL Server Agent Jobs zum Protokollieren im Event Log

(Zum Vergößern auf das Bild klicken)

Solange die Quelle des SSIS-Pakets bekannt ist, ist alles wie erwartet. Im Eventlog werden folgende 3 Events festgehalten (da ja mein Script-Task dazu führt, dass das Paket auf einen Fehler läuft):

Die Events, die durch ein Paket mit vorhandener Connection erzeugt werden

Die Meldungen sind:

  1. Starten des SSIS Pakets (Information)
  2. Fehler des SSIS Pakets (Fehler)
  3. Fehler des SQL Server Agent Jobs (Warnung)

Letzte Meldung sieht im Detail so aus:

Ereignis-Details der SQL Server Agent-Meldung, dass der Job nicht erfolgreich war

Wenn ich jetzt aber die Connection des Statements „SELECT 1“ ändere, so dass der dort angegebene Computer nicht existiert, passiert folgendes, wenn das Paket im SQL Server Agent gestartet wird:

Ereignisanzeige, wenn die Connection des SSIS Pakets nicht validiert werden kann

Man sieht, dass die SSIS-Eventlog-Einträge nicht vorhanden sind. Dies liegt daran, dass der Fehler beim Validieren auftritt und deshalb das Paket noch gar nicht angelaufen ist.

Deswegen macht es keinen Sinn, die SSIS-Eventlog-Einträge für eine Überwachung der Jobs zu verwenden.

Stattdessen können die SQL Server Agent-Einträge überwacht werden. Dabei ist aber zu beachten, dass dies bei jedem SQL Server Agent Job – wie oben gezeigt – eingestellt werden muss.

MDX-Skripte eines Cubes über C#-Code anpassen

Zu dem Standard-Aufgaben bei SSAS-Projekten gehören KPIs, wobei Ist- und Planwerte verglichen und danach der Status einer KPI berechnet wird. Heute möchte ich mich auf den Status fokusieren.

Eine normale Regel könnte sein:

  • Wenn Ist >= Plan, dann Status grün
  • Wenn Ist >= 90% des Plans, dann Status gelb
  • Sonst Rot

Das sähe im MDX-Skript in etwa so aus:

CREATE MEMBER CURRENTCUBE.[Measures].[OPE_Status]
AS iif( [Measures].[OPE] >= [Measures].[OPE_Plan] , 1,
iif( [Measures].[OPE] >= [Measures].[OPE_Plan] * 0.9, 0, -1)),
VISIBLE = 1;

oder

OPE_Status

Dabei steht verabredungsgemäß +1 für grün, 0 für gelb, -1 für rot (wenn es natürlich auch andere Möglichkeiten gibt).

Möglicherweise will man nun aber den Faktor 90% für die Schwelle zwischen Gelb und Rot (oder auch den Schwellwert 100% für die Grenze zwischen Grün und Gelb) dynamisch gestalten – zum Beispiel durch die Eingabe in einer Administrationskonsole. Dann wäre es schön, wenn man dieses MDX dynamisch anpassen könnte.

Deswegen beschreibe ich hier, wie das geht:

Als erstes muss in C# der Verweis Microsoft.AnalysisServices eingebunden werden. Verwirrenderweise findet man diesen nicht unter Microsoft…, sondern unter Analysis Management Objects (kurz AMO):

Verweis

Diesen Namespace verwendet man mit

using SSAS = Microsoft.AnalysisServices;

Danach geht es recht einfach:

SSAS.Server server = new SSAS.Server();

try
{
server.Connect(„Data source=<SSAS-Servername>“);
SSAS.Database db = server.Databases.FindByName(„<SSAS-Datenbankname>“);
SAS.Cube cb = db.Cubes.FindByName(„<SSAS-Cubename>“);
}
catch (Exception e) …

Auf die MDX-Skripte hat man dann mit

cb.MdxScripts[0].Commands[0].Text

Zugriff. Diesen String kann man dann auch manipulieren. Damit die Veränderungen auf den Analysis Services gespeichert werden, muss man die Änderungen mit

cb.MdxScripts[0].Update();

speichern.

Ich empfehle die dynamischen MDX-Anteile von den statischen durch Kommentare wie

/*Beginn Statusberechnungen*/n/* Den Text zwischen diesen Markierungen NICHT verändern, da er autogeneriert ist*/n

/* Ende Statusberechnungen */

voneinander zu trennen.

Dann kann man auch durch einfache String-Manipulation den zu ändernden Teil herausfischen, ihn ändern und wieder zurückschreiben, ohne den kompletten Cube zu zerstören 🙂

Natürlich muss obiges nicht in einem eigenen C#-Programm programmiert werden, es kann auch als Teil eines SSIS-Pakets verwendet werden.

In einem meiner Projekte verwendete ich einen Data Flow Task, in dem ich die einzelnen Status-Formeln berechnete und in einer Skriptkomponente (als Ziel) die MDX-Skripte in dem Cube aktualisierte. Den Code für die Skriptkomponente habe ich hier als Anlage beigefügt. (Das ist offensichtlich SQL Server 2008, da C# ja erst dann verwendet werden kann 🙂 )

Automatisierung von Analysis Services-Aufgaben über XMLA

Alle Aufgaben, die man im SQL Server Management Studio für den Betrieb eines SQL Server Analysis Services vornehmen kann, können auch über XMLA gesteuert werden.

Das gilt zum Beispiel für das Aufbereiten (Verarbeiten, process) von Cubes oder dem Backup von Datenbanken. Ich werde mich heute mit dem Backup einer Analysis Services – Datenbank beschäftigen.

Das Schöne ist, dass wir gar nicht die Syntax der XMLA nachschlagen müssen. Das SQL Server Management Studio erstellt uns nämlich den notwendigen XMLA-Code automatisch (und das gilt für beide Versionen 2005 und 2008). Dazu wählen wir zunächst im Kontextmenü die gewünschte Aktion aus:

BackUp in SQL Server Management Studio

Dann startet sich ein Popup-Fenster, in dem wir die gewünschten Einstellungen durchführen, aber nicht auf OK klicken.

Script Button oben

Im oberen Bereich befindet sich eine Script-Button. Wenn man auf diesen klickt, wird das zugehörige XMLA erstellt:

Backup-XMLA

Dies kann man jetzt sogar direkt im SQL Server Management Studio ausführen (Execute!).

Bei Erfolg liefert die Ausführung folgendes Ergebnis:

<return xmlns=“urn:schemas-microsoft-com:xml-analysis“>
<root xmlns=“urn:schemas-microsoft-com:xml-analysis:empty“ />
</return>

Das Problem (auf das wir später noch zurückkommen werden) ist, dass auch bei einem Fehler in der Regel kein Fehler geschmissen wird (bei Analysis Services 2008 kommen manchmal Fehler vor), sondern ein XML zurückgegeben wird, in der die XML-Knoten Exception oder Error oder ähnliches auftauchen. Wie gesagt, dazu später mehr.

Wie können wir nun ein solches XMLA automatisiert (zeitgesteuert) aufrufen?

Die einfachste Möglichkeit ist über den SQL Server Agent. Wir legen dazu einen neuen Job an. Der erste Schritt des neuen Jobs sieht so aus:

Step zum Backup via XMLA

Wie man in obigem Screen Shot sieht, muss als Typ „SQL Server Analysis Services Command“ ausgewählt, als Server dergewünschte SQL Server Analysis Services-Server (hier im Beispiel ssasentsql2008) eingetragen und das XMLA in die große Textbox Command kopiert werden.

Damit kann dieses XMLA im Rahmen eines SQL Server Agent Jobs ausgeführt werden.

Im Log File Viewer kann man nach der Ausführung das ERgebnis der Ausführung wie folgt erkennen:

Log File Ergebnis der Ausführung eines XMLA Befehles

Was ich markiert habe, ist genau das Ergebnis, das wir vorhin auch als Ergebnis bei der Ausführung im SQL Server Management Studio gesehen hatten. Hier erkennt man, dass die Ausführung erfolgreich war, weil das Ergebnis „empty“ ist. Natürlich wird der Job als erfolgreich beendet angezeigt.

Das Problem hierbei ist, dass bei Fehlern bei der Ausführung der Job ebenfalls als erfolgreich abgeschlossen angezeigt wird und die Fehlermeldung nur an dieser Stelle im Log sichtbar ist.

Ausgabe, wenn das XMLA einen Fehler geliefert hat

Man erkennt deutlich, dass der Step als erfolgreich markiert ist, aber offensichtlich nicht erfolgreich durchgeführt wurde. Die Fehlermeldung habe ich markiert. (In dem Beispiel handelte es sich um das Aufbereiten einer nicht existenten Datenbank)

Dies ist natürlich sehr ungünstig, da Administratoren auf das Fehlschlagen eines Jobs reagieren können, aber nicht auf irgendwo enthaltene Fehlermeldungen. Deswegen empfehle ich, in produktiven Umgebungen das XMLA nicht direkt im SQL Serevr Agent auszuführen, sondern, wie gleich beschrieben im SSIS. Im SQL Server Agent 2008 scheint dieses Problem behoben zu sein. Wenn man obigen fehlerhaften Job im SQL Server Agent 2008 anlegt (sogar auch wenn man als Ziel des XMLA sogar einen 2005er Analysis Services wählt), wird der Fehler im SQL Server Agent erkannt und sinnvoll protokolliert, wie man in folgendem Screen Shot sehen kann:

Fehler in XMLA korrekt erkannt

Nun aber zu einer anderen Möglichkeit, das XMLA auszuführen, als Integration Services Package im SSIS:

Im Control Flow gibt es dort eine Task mit Titel Analysis Services Execute DDL Task. Diese benötigt eine Cube-Connection und das zu automatisierende XMLA. Das XMLA kann dabei direkt eingegeben oder aus einer Variable oder aus einem File ausgelesen werden. Letzters wird bei großen XMLAs benötigt, da sonst die Größenbeschränkung auf ca. 4000 Zeichen besteht.

Bild

Unter diesem Link habe ich ein einfaches Paket zum Download bereit gestellt, dass nach Eingabe einiger Variablen das XMLA automatisch erstellt (über Expressions der Execute SSAS DDL Task) und dann ausführt. Die Variablen sind im beigefügten Config-File enthalten, so dass Sie das Paket auch einfach über die Anpassungen an dieser Config-Datei steuern können.

Als Variablen werden verwendet:

  • CubeDatenbank: Die SSAS-Datenbank, die gesichert werden soll.
  • CubeServer: Der Name des SSAS-Servers, auf dem sich die zu sichernde Datenbank befindet.
  • Dateiname: Name der zu erstellenden Datei
  • MitKompression: Soll die Datei komprimiert werden? (im Config-File 0 für nein, 1 für ja eintragen)
  • mitUeberschreiben: Soll evtl. eine bereiots existierende Datei überschrieben werden? (im Config-File 0 für nein, 1 für ja eintragen)
  • BackupPasswort: Geben Sie das an, wenn Sie Ihr Backup verschlüsseln wollen, sonst leer lassen (dann wird nicht mit leerem Passwort verschlüsselt 🙂 )

Variablen fürs SSIS Backup

Ganz analog können alle XMLAs mit SSIS ausgeführt werden.

Bug im Visual Studio 2008: SSIS Variablenänderung bei F5-Start Debug

Im Visual Studio 2008 tritt bei SSIS-Paketen ein kleiner – aber gemeiner – Bug auf.

Ändert man eine Variable und drückt, während man noch in der Variable steht, F5, um die Debug-Ausführung des Paktes zu starten, dann startet das Paket noch mit dem alten Wert der Variable. Wie man im Screenshot schön sieht, ist die Paketvariable auf „Neuer Text“ gesetzt worden, allerdings wird in der Messagebox noch der alte Inhalt „Hallo Welt“ angezeigt.

Variableninhalt falsch angezeigt bei F5

Das Phänomen tritt auf, egal ob man F5 drückt oder den grünen Button Grüner Pfeil betätigt, solange man zu diesem Zeitpunkt in der Spalte „Value“ der Variable steht. Sobald man diese Spalte verlassen hat (z.B. durch Anklicken der Spalte „Data Type“) funktioniert es korrekt.

Meine Erfahrungen in der Business Intelligence Welt