Datenimport mit fabasoft Components/COLD

Werbung
Datenimport mit
fabasoft Components/COLD
Hannes Mahringer
ISBN: 978-3-902495-24-2
Alle Rechte der Verbreitung, auch durch fotomechanische Wiedergabe,
Tonträger jeder Art, auszugsweisen Nachdruck oder Einspeicherung und
Rückgewinnung in Datenverarbeitungsanlagen aller Art, sind vorbehalten.
Es wird darauf verwiesen, dass alle Angaben in diesem Fachbuch trotz
sorgfältiger Bearbeitung ohne Gewähr erfolgen und eine Haftung der Autoren oder
des Verlages ausgeschlossen ist.
Aus Gründen der einfacheren Lesbarkeit wird auf die geschlechtsspezifische
Differenzierung, z.B. Benutzer/-innen, verzichtet. Entsprechende Begriffe gelten im
Sinne der Gleichbehandlung grundsätzlich für beide Geschlechter.
Fabasoft und das Fabasoft Logo sind registrierte Warenzeichen der Fabasoft AG.
Microsoft, MS-DOS, Windows, das Windows-Logo, Windows 95, Windows 98,
Windows Me, Windows XP, Windows NT, Windows 2000, Windows Server,
Active Directory, Outlook, Excel, Word, PowerPoint, Visual Studio, Visual Basic,
Visual C++ sind entweder registrierte Warenzeichen oder Warenzeichen
der Microsoft Corporation.
Alle anderen verwendeten Hard- und Softwarenamen sind
Handelsnamen und/oder Marken der jeweiligen Hersteller.
© Fabasoft International Services GmbH, Linz 2007
Honauerstraße 4, 4020 Linz
Tel.: +43 (732) 606162
http://www.fabasoft.at
Datenimport mit Fabasoft Components/COLD
Hannes Mahringer
Inhaltsverzeichnis
2007
Datenimport mit Fabasoft Components/COLD
1
2
Einleitung
______________________________________________________
______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Datenimportobjekte
______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
1
11
13
2.1 Ablauf eines Imports ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 13
2.2 Zuordnung der Spalten zu Eigenschaften ____________________________ 13
2.3 Tracing in Fabasoft Components Expressions ______________________________________________________________________________________________________________________________________________________________________________________________________________ 21
Datenquelle ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 21
Zuordnungen von Eigenschaften ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 23
Suchen und Erzeugen von Objekten ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 24
Importieren der Daten __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 24
3
Ablauf eines Datenimports
4
Datenimportobjekt
__________________________________________________________________________________________________________________________________________________________________________________________________________________________
__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
27
31
4.1 Datenquellen ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 39
Auswahl des Datenbereichs __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 39
4.2 Objektklassen
________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
40
5
4.3 Setzen und Ändern von Eigenschaften ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Eigenschaften ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Objektbeziehungen ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Schlüsseleigenschaften und Änderung von Werten ______________________________________________________________________________________________________________________________________________________________________________________________________
Setzen von Inhaltseigenschaften ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Zeichenkettenlisten ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Zusammengesetzte Eigenschaften ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Verarbeitung von Listen ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
40
4.4 Identifikation und Duplikatsprüfung ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Objektsuche ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Suchbereiche ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Objektsperren ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
55
40
42
42
46
48
49
51
55
67
68
4.5 Parameter der Verarbeitung ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 69
Transaktionen und Threads __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 69
Übergehen von Methoden ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 72
4.6 Importoptionen und Protokoll ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Protokoll: Modus, Objekt, max. Einträge ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Änderungen sofort anzeigen __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Objekte nicht aktualisieren __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
74
4.7 Skripts ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Filterskript für Rohdaten __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Filter für Objekte ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Filter für Objekte nach dem Commit ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
75
74
74
75
76
77
79
5
Was man unbedingt beachten sollte …
______________________________________________________________________________
81
5.1 Nummeratoren ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 81
Nummerator-Eigenschaften ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 81
Schlüssel-Nummerator ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 83
5.2 Protokoll
__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
5.3 Roll-Forward
________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
84
85
5.4 Starten des Datenimports ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 88
Ferngesteuertes Importieren __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 88
6
Optimierung
______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
93
6.1 Struktur des Datenimports __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Abhängigkeiten ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Migrationszwischenformat __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Zusammenfassen von Importen ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Aufteilung von Importen __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
93
93
96
97
97
6.2 Optimierungsoptionen des Imports ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 97
Algorithmen zur Vermeidung doppelter Objekte ____________________________________________________________________________________________________________________________________________________________________________________________________________________________ 99
Sortierung __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 99
Parallelisierung ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 101
6.3 Client-Optimierung __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 102
Client-Cache ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 102
Netzwerkanbindung __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 103
Client-CPUs __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 104
Festplatte ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 104
Anzahl der Clients ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 105
7
6.4 Fabasoft Components COO-Service-Optimierung ____________________________________________________________________________________________________________________________________________________________________________________ 105
Anzahl der Worker Threads ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 105
Fabasoft Components COO-Service-Cache __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 107
Objektsperren ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 107
6.5 Optimierungen am Datenbanksystem ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 107
Backup, Restore und Recovery ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 108
Indizes und Statistiken __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 108
Tabellendefinitionen ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 110
Auto-Grow ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 112
Device-Placement ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 112
6.6 Fabasoft Components MMC-Service-Optimierung
____________________________________________________________________________________________________________________________________________________________________________
113
6.7 Von Objekten und Töpfen __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 113
Statische Problemanalyse ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 114
Dynamische Problemanalyse ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 115
Performance Monitor/SNMP ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 117
Counter des Fabasoft Components Kernels ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 121
Counter der Fabasoft Components Services __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 124
6.8 Der Kernel-Trace ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 125
Erstellen der Traces ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 125
Interpretation des Traces ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 126
7
Konfiguration der Datenquellen
________________________________________________________________________________________________________________________________________________________________________
131
7.1 ODBC ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 135
Microsoft Excel ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 135
CSV und Tab-Separated Files ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 136
Oracle unter Linux ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 139
7.2 OLE DB ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 139
Definition der OLE DB-Datenquelle ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 140
Microsoft SQL Server __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 142
Microsoft Access ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 142
File Provider ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 143
7.3 Report-Umsetzer __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 147
7.4 Skript-Datenquelle
__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
149
7.5 LDAP-Datenquelle
______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
155
7.6 ADE DB ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 156
7.7 CSV
____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
157
7.8 Roll-Forward Log-Reader ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 157
8
Zusätzliche Beispiele
______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
159
8.1 Datenquellenskript __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 159
XML-Datenquelle ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 159
8.2 Filterskript für Rohdaten ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 160
Berechnete Spalten ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 160
Berechung der Werte aus der LDAP-Datenquelle ____________________________________________________________________________________________________________________________________________________________________________________________________________________ 164
8.3 Filterskript für Objekte __________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 166
Versionierung ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 166
8.4 Filterskript für Objekte nach dem Commit ________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 168
Archivierung ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 168
9
Glossar
10
Abbildungsverzeichnis
11
__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Literaturverzeichnis
171
______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
173
____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
175
9
1
11
1 Einleitung
Dieses Buch ist für all jene geschrieben, die Daten in Fabasoft Components Domänen importieren
wollen. Die Softwarekomponente Fabasoft Components/COLD ([email protected]) bietet ein mächtiges und – bei richtiger Konfiguration – sehr effizientes Werkzeug um Daten aus verschiedensten
Datenquellen zu lesen und auf das Objektmodell der konkreten Installation abzubilden.
Das Buch besteht aus mehreren Teilen:
°
In Kapitel 2 werden anhand eines anschaulichen Beispieles die Grundfunktionen des Datenimports mit
Fabasoft Components/COLD erklärt.
°
°
°
°
°
°
Kapitel 3 widmet sich dem Ablauf eines Datenimports.
Kapitel 4 schafft einen Einblick in die Details der Konfiguration von Datenimportobjekten.
In Kapitel 5 gibt es Wissenswertes rund um den Datenimport zu lesen.
Kapitel 6 behandelt die Optimierung der Imports auf allen Ebenen.
Eine Anleitung zur Konfiguration der verschiedenen Datenquellen ist in Kapitel 7 zu finden.
Zuletzt werden in Kapitel 8 noch einige Konfigurationsbeispiele und Skripts erklärt.
2
13
2 Ein Beispiel für den Anfang
Die Zielsetzung von Fabasoft Components/COLD ist es, Daten einfach konfigurierbar und effizient in
eine Fabasoft Components Domäne importieren zu können. Dieses Kapitel ist eine Einführung in die
Verwendung von Fabasoft Components/COLD und ist für jene Anwender gedacht, die noch keine
Erfahrungen damit haben. Dabei werden die Grundlagen anhand eines einfachen Beispiels erklärt.
2.1
Ablauf eines Imports
Bei einem Datenimport werden Daten aus einer Datenquelle gelesen und in der Fabasoft Components Domäne
auf bestehende oder neue Objekte übertragen. Wie diese Übertragung stattfindet, genauer gesagt welche
Werte der Quelldaten in welche Eigenschaften welcher Zielobjekte geschrieben werden, wird in Datenimportobjekten definiert. Der Import wird dann durch den Aufruf der Import-Methode dieses Datenimportobjekts gestartet. Das kann entweder über das Kontextmenü oder durch den direkten Aufruf der Importmethode, zum Beispiel
von einem Skript aus, erfolgen.
2.2
Zuordnung der Spalten zu Eigenschaften
Bevor wir uns auf die Konfiguration der Datenimportobjekte stürzen, sehen wir uns die Zuordnung der Daten zwischen Datenquelle und Zielobjekten an. Die Daten der Datenquelle bestehen im Allgemeinen aus einer oder
mehreren Zeilen (Records) die alle die gleichen Spalten (Columns) enthalten, auch wenn nicht immer jede dieser Spalten in jeder Zeile einen Wert enthalten muss.
Beispiel: „Customers“ aus der „Northwind“-Datenbank
Microsoft hat bis zum Microsoft SQL Server 2000 eine Demo-Datenbank mit dem Namen Northwind
mit dem Produkt mitgeliefert. Diese ist bis heute auch als Download frei verfügbar und kann auch am
Microsoft SQL Server 2005 verwendet werden. In dieser Datenbank gibt es eine Tabelle Customers, die
91 Datensätze mit Kundendaten enthält. Diese eignen sich dazu, in eine Fabasoft Components Domäne
geladen zu werden. Aus diesen Daten sollen Personenobjekte und Organisationen erzeugt werden.
Tabelle 1 zeigt das Format der Quelldaten, so wie sie in der Datenbank zur Verfügung stehen.
COLUMN NAME
TYPE
LENGTH
NULLABLE
CustomerID
nchar
5
No
CompanyName
nvarchar
40
No
ContactName
nvarchar
30
Yes
ContactTitle
nvarchar
30
Yes
Address
nvarchar
60
Yes
City
nvarchar
15
Yes
Region
nvarchar
15
Yes
PostalCode
nvarchar
10
Yes
Country
nvarchar
15
Yes
Phone
nvarchar
24
Fax
nvarchar
24
Yes
Yes
Tabelle 1: Format der Quelldaten
Man sieht, dass alle Spalten als Textspalten deklariert sind. Die CustomerID eignet sich hervorragend als
Schlüsseleigenschaft für die Person, der CompanyName ist als einzige Eigenschaft der Organisation gleichzeitig die Schlüsseleigenschaft der Organisation. Tabelle 2 und Tabelle 3 enthalten die zu verwendenden Eigenschaften der Zielobjektklassen:
2. Ein Beispiel für den Anfang
2.2 Zuordnung der Spalten zu Eigenschaften
Person
NAME
REFERENZ
TYPE
LÄNGE
Externer Schlüssel
[email protected]:objexternalkey
STRING
254
Vorname
[email protected]:userfirstname
STRING
64
Nachname
[email protected]:usersurname
STRING
64
Organisation.
Orgnaisation
[email protected]:persjobs.
[email protected]:joborganization
STRING
80
Organisation.
Position/Tätigkeit
[email protected]:persjobs.
[email protected]:jobfunction
STRING
80
Adresse.Adresstyp
[email protected]:address.
[email protected]:addrtype
ENUM
Adresse.Straße
[email protected]:address.
[email protected]:addrstreet
STRING
80
Adresse.Ort
[email protected]:address.
[email protected]:addrcity
STRING
60
Adresse.Bundesland
[email protected]:address.
[email protected]:addrstate
STRING
60
Adresse.
Postleitzahl
[email protected]:address.
[email protected]:addrzipcode
STRING
20
15
NAME
REFERENZ
TYPE
LÄNGE
Adresse.Land
[email protected]:address.
[email protected]:addrcountry
STRING
60
Telefonnummern.Typ
[email protected]:telephones.
[email protected]:teltype
ENUM
Telefonnummern.
Telefonnummer
[email protected]:telephones.
[email protected]:telnumber
STRING
32
Tabelle 2: Eigenschaften der Objektklasse Person
Organisation
NAME
REFERENZ
TYPE
LÄNGE
Kurzname
[email protected]:orgshortname
STRING
50
Tabelle 3: Eigenschaft der Objektklasse Organisation
Wenn man die Quelldaten mit den Zieldaten vergleicht, so stößt man auf folgendes Problem: Die Spalte
ContactName beinhaltet sowohl den Vor- als auch den Nachnamen der Person. Dieser Wert muss also
zuerst in zwei Teile „zerlegt“ werden, bevor er den beiden Eigenschaften Vorname und Nachname zugeordnet
werden kann. Dafür werden in weiterer Folge zwei Lösungen gezeigt.
1. Am Microsoft SQL Server kann eine View definiert werden, in der aus dem ContactName zwei Spalten,
ContactFirstname und ContactLastname, berechnet werden.
2. Ein Beispiel für den Anfang
2.2 Zuordnung der Spalten zu Eigenschaften
2. Im Filterskript für Rohdaten des Datenimportobjekts kann der ContactName in zwei berechnete
Spalten aufgeteilt werden. Dieses Skript finden Sie als Beispiel auf Seite 161.
Wenden wir uns also der ersten Lösungsmöglichkeit zu:
Eine SQL-View definiert eine Sicht auf die bestehenden Daten, in der neben den Originaldaten auch berechnete Spalten enthalten sein können. In unserem Fall sollen zwei zusätzliche Spalten definiert werden. Für die
Berechnung wird der erste Teil des Namens bis zum ersten Leerzeichen als Vorname in der Spalte
ContactFirstname, und der Rest nach dem Leerzeichen als Nachname in der Spalte
ContactLastname interpretiert. Die View, wie sie in Quelltext 1 dargestellt ist, funktioniert zwar nicht bei
allen Einträgen, dies ist aber für dieses Beispiel unerheblich („Miguel Angel Paolino“ und „José Pedro Freyre“
mögen mir verzeihen).
CREATE VIEW CustomersNameView AS
SELECT SUBSTRING(ContactName, 1, CHARINDEX(' ', ContactName)) AS
ContactFirstname,
SUBSTRING(ContactName, CHARINDEX(' ', ContactName) + 1, 200) AS
ContactLastname, *
FROM Customers
Quelltext 1: SQL-View CustomersNameView
Aus den vorangegangenen Tabellen ergibt sich bei Verwendung der CustomersNameView die Zuordnung
der Spalten zu den einzelnen Eigenschaften der Objekte:
17
SPALTE/WERT
OBJEKTKLASSE
EIGENSCHAFT
REFERENZ
DER EIGENSCHAFT
CustomerID
Person
Externer
Schlüssel
[email protected]:
objexternalkey
CompanyName
Organisation
Kurzname
[email protected]:
orgshortname
ContactFirstname
Person
Vorname
[email protected]:
userfirstname
ContactLastname
Person
Nachname
[email protected]:
usersurname
<Organisation>
Person
Organisation.
Orgnaisation
[email protected]:
persjobs.
[email protected]:
joborganization
ContactTitle
Person
Organisation.
Position/
Tätigkeit
[email protected]:
persjobs.
[email protected]:
jobfunction
"1"
Person
Adresse.
Adresstyp
[email protected]:
address.
[email protected]:
addrtype
2. Ein Beispiel für den Anfang
2.2 Zuordnung der Spalten zu Eigenschaften
SPALTE/WERT
OBJEKTKLASSE
EIGENSCHAFT
REFERENZ
DER EIGENSCHAFT
Address
Person
Adresse.Straße
[email protected]:
address.
[email protected]:
addrstreet
City
Person
Adresse.Ort
CISB[email protected]:
address.
[email protected]:
addrcity
Region
Person
Adresse.
Bundesland
[email protected]:
address.
[email protected]:
addrstate
PostalCode
Person
Adresse.
Postleitzahl
[email protected]:
address.
[email protected]:
addrzipcode
Country
Person
Adresse.Land
[email protected]:
address.
[email protected]:
addrcountry
19
SPALTE/WERT
OBJEKTKLASSE
EIGENSCHAFT
REFERENZ
DER EIGENSCHAFT
"400"
Person
Telefonnummern.
Typ
[email protected]:
telephones.
[email protected]:
teltype
Phone
Person
Telefonnummern.
Telefonnummer
[email protected]:
telephones.
[email protected]:
telnumber
"405"
Person
Telefonnummern.
Typ
[email protected]:
telephones.
[email protected]:
teltype
Fax
Person
Telefonnummern.
Telefonnummer
[email protected]:
telephones.
[email protected]:
telnumber
Tabelle 4: Zuordnung der Datenbankspalten zu Eigenschaften von Objekten
Zusätzlich zu den Werten der Datenbanken werden hier für die Typ-Eigenschaften der Adresse und der Telefonnummern Konstanten verwendet, die sich aufgrund der Bedeutung der Werte ergeben. So steht zum Beispiel die
Zahl „405“ in der vorletzten Zeile der Tabelle für den Aufzählungswert „Fax“ des Typs der Telefonnummer.
2. Ein Beispiel für den Anfang
2.2 Zuordnung der Spalten zu Eigenschaften
2.3 Datenimportobjekte
2.3
Datenimportobjekte
Wie alles in Fabasoft Components werden auch Datenimporte in Form von Objekten definiert – den Datenimportobjekten. Es gibt zwei Objektklassen dafür, die von der Funktionalität her äquivalent sind und sich nur
dadurch unterscheiden, dass die eine von der Objektklasse Konfigurationsobjekt abgeleitet ist und die
andere von Basisobjekt. Komponentenobjekte haben den Vorteil, im Rahmen von Softwarekomponenten
extrahiert und in anderen Fabasoft Components Domänen wieder geladen werden zu können, während die„normalen“ Datenimportobjekte ohne Softwarekomponente lokal in einer Fabasoft Components Domäne angelegt werden können, damit aber weniger leicht in andere Installationen transportiert werden können.
Für die Definition und die Durchführung der Datenimporte ist dieser Unterschied jedoch unerheblich und so wird
in weiterer Folge nur von Datenimportobjekten gesprochen und es sind damit, sofern nicht explizit darauf eingegangen wird, beide Ausprägungen dieser Objekte gemeint.
Wird nun ein Datenimportobjekt angelegt und über den Menübefehl Eigenschaften bearbeiten aus dem Kontextmenü geöffnet, besteht die erste Aufgabe darin, die Verbindung zur Datenquelle herzustellen.
Datenquelle
In unserem Beispiel gehen wir davon aus, dass die Quelldaten in einer Microsoft SQL Server-Datenbank am lokalen Rechner in einer Datenbank mit dem Namen Northwind in der Tabelle CustomersNameView
stehen. Andere Datenquellen sind ähnlich zu verwenden und es wird im Kapitel „Konfiguration der Datenquellen“ auf Seite 131 im Detail auf die Konfiguration und Verwendung der verschiedenen Datenquellen eingegangen.
Die beste Möglichkeit auf eine Microsoft SQL Server-Datenbank unter Microsoft Windows zuzugreifen ist die
Verwendung des OLE DB-Providers für den SQL Server.
21
Dazu wird, wie in Abbildung 1 ersichtlich, als Datenquelle „OLE DB“ ausgewählt und als Verbindungsparameter
„Provider=SQLOLEDB;Datasource=localhost;Catalog=Northwind“ angegeben. Damit wird definiert, dass die Verbindung über den OLE DB-Provider „SQLOLEDB“ zu Datenbank Northwind auf dem lokalen Rechner „localhost“ hergestellt wird. In der Eigenschaft Tabelle wird der Name der Tabelle oder View, also in unserem Fall
CustomersNameView eingegeben und damit ist die Datenquelle fertig definiert.
Abbildung 1
Customers: Datenquelle und
Zuordnungen
2. Ein Beispiel für den Anfang
2.3 Datenimportobjekte
Zuordnungen von Eigenschaften
Nun folgt der Schritt, der in Tabelle 4 bereits vorbereitet wurde: Die Abbildung der Spalten der Quelldatenbank
auf Eigenschaften von Objekten. Dazu wird für jede der Zeilen in der Tabelle eine Zeile in der zusammengesetzten Eigenschaft Zuordnung definiert (siehe Abbildung 1).
Um in den Zuordnungen zwischen Telefon- und Faxnummer zu unterscheiden, wird bei einer Faxnummer die
Objekt-ID „1“ gesetzt.
Die Objektbeziehung zwischen Organisation und Person wird nun, wie in Abbildung 2 ersichtlich, in der Tabelle
Objektbeziehungen definiert.
Abbildung 2
Customers: Objektbeziehungen und Klasseneigenschaften
23
Suchen und Erzeugen von Objekten
Die Klasseneigenschaften legen vor allem fest, wie die Objekte gesucht und ob sie erzeugt werden sollen. In
unserem Beispiel werden die in Abbildung 2 angeführten Einstellungen verwendet.
In diesem Fall wird in der Fabasoft Components Domäne nach bestehenden Objekten mit den definierten Schlüsseleigenschaften gesucht. Wird ein Objekt nicht gefunden, so wird es neu erzeugt. Bei der Person mit der ObjektID „1“, die für den zweiten Eintrag in die Liste der Telefonnummern benötigt wurde, wird hier definiert, dass für
die Person mit ID „1“ dasselbe Objekt, wie bei der Person mit der niedrigeren ID – also „0“ – verwendet wird.
Importieren der Daten
Der Import kann nun, wie in Abbildung 3 dargestellt, aus dem Kontextmenü des Datenimportobjekts mit dem
Menübefehl Daten importieren gestartet werden.
Alternativ dazu kann ein Datenimport auch durch Skripts, Fabasoft Components Expressions oder durch einen
Fabasoft Components AT-Job gestartet werden.
2. Ein Beispiel für den Anfang
2.3 Datenimportobjekte
Abbildung 3
Customers: Daten
importieren
25
3
27
3 Ablauf eines Datenimports
In diesem Kapitel werden anhand der Datenflüsse die am Import beteiligten Komponenten erklärt.
Dieses Verständnis ist die Voraussetzung dafür, dass die Auswirkungen der Konfigurationsmaßnahmen richtig eingeschätzt werden können und danach die richtigen Optimierungsmaßnahmen
ergriffen werden.
Abbildung 4
Datenfluss bei der
Verarbeitung eines
Datenimports
Betrachtet man die Endpunkte eines Datenimports in Abbildung 4, so erkennt man, dass ein Datenimport eine
Transformation von Daten, die in einer Datenbank oder einer Dateistruktur vorliegen, in eine andere Form
auf einer anderen Datenbank und/oder Dateistruktur darstellt. Dazwischen liegen die Services der Fabasoft
Components Domäne. Auf dem Fabasoft Components Kernel wird der eigentliche Importvorgang ausgeführt, und
die Fabasoft Components Backendservices übernehmen die Umsetzung der Objektstruktur des Fabasoft
Components Kernels in das Format zur Speicherung in der Datenbank bzw. im Dateisystem.
Betrachtet man den Datenimport am Fabasoft Components Kernel näher, so erkennt man, dass auch hier unterschiedliche Prozesse (Threads) an der Verarbeitung beteiligt sind. Neben dem Import Thread, der die Steuerung
der Abläufe übernimmt, ist das der Reader Thread, der die Daten der Datenquelle liest und in Paketen zur Weiterverarbeitung an einen oder mehrere Worker Threads übergibt. Diese Worker Threads übernehmen die Umsetzung der Werte aus dem Quellformat in die Objektwelt von Fabasoft Components. Diese Worker Threads sind
es auch, die mit den Fabasoft Components Backendservices kommunizieren, sei es bei der Objektsuche oder
beim Commit der Transaktionen, also beim Schreiben der Änderungen auf die Fabasoft Components COO- und
MMC-Services.
Auch auf den Fabasoft Components COO- und MMC-Services ist ein Pool von Worker Threads für die Bearbeitung der Anforderungen von den einzelnen Fabasoft Components Kernels verfügbar. Hier wird eine Maximalzahl
der Worker Threads konfiguriert und damit die maximale Parallelität des jeweiligen Services definiert. Werden
gleichzeitig mehr Anfragen an eines der Fabasoft Components Backendservices gestellt als bei diesem Worker
Threads definiert sind, so müssen die überzähligen Anfragen auf das Freiwerden eines Threads warten.
Im Bereich der Datenspeicherung in der Datenbank und dem Dateisystem werden die Änderungen in Form von
Datensätze und Dateien persistiert.
3. Ablauf eines Datenimports
29
4
31
4 Datenimportobjekt
Wenden wir uns nun der Konfiguration des Datenimports zu. Wie in Fabasoft Components üblich,
erfolgt diese Konfiguration in Form von Objekten – den Datenimportobjekten – in der Fabasoft Components Domäne.
Die Datenimportobjekte gibt es in zwei Ausprägungen: Als normales Datenimportobjekt
([email protected]:DataImport) abgeleitet von Basisobjekt ([email protected]:
BasicObject)
und
als
Datenimport-Komponentenobjekt
([email protected]:
DataImportComponentObject) abgeleitet von Konfigurationsobjekt ([email protected]:
ConfigurationObject), das sich von dessen Basisklasse Komponentenobjekt
([email protected]:ComponentObject) durch die häufigere Aktualisierung unterscheidet. Die beiden
Datenimportobjektklassen haben dieselben Eigenschaften zugeordnet, nur dass das Komponentenobjekt zusätzlich die drei Eigenschaften Softwarekomponente ([email protected]:component), Referenz
([email protected]:reference) und Gelöscht ([email protected]:deleted) erbt und daher im
Rahmen einer Softwarekomponente transportiert werden kann. Im sonstigen Verhalten unterscheiden sich
diese beiden Objektklassen nicht und daher wird im Weiteren nicht zwischen diesen beiden Ausprägungen
unterschieden und allgemein von Datenimportobjekten gesprochen, womit jedoch beide Arten gemeint sind.
Die Eigenschaften des Datenimportobjekts werden in mehrere Gruppen eingeteilt, auf die im späteren Verlauf
dieses Kapitels weiter eingegangen wird:
Definition der Datenquelle
Ein Beispiel für diese Eigenschaften finden Sie in Abbildung 1.
°
Datenquelle ([email protected]:datimpdatasourcetype und [email protected]:
datimpdatasource): Gemeinsam definieren diese beiden Eigenschaften die Verbindung zur Datenquelle.
°
Datenquellenobjekt ([email protected]:datimpobjdatasource): Objekte dieser Eigenschaft werden bei dateibasierten Quelldatenformaten als Datenquelle verwendet. Unterstützt werden dabei
Dokumente, deren Hauptinhalt die Endung „xls“ oder „csv“ hat. Diese werden mit den passenden ODBCTreibern geöffnet, was jedoch nur auf der Microsoft Windows-Plattform funktioniert.
°
Tabelle ([email protected]:datimpsourcetable): Hier wird der Name der Tabelle angegeben.
Zuordnung der Werte und Referenzen zu den Eigenschaften
°
Zuordnung ([email protected]:datimpmapping): In dieser Liste werden die einzelnen
Zuordnungen von Datenbankspalten bzw. Festwerten zu den jeweiligen Eigenschaften vorgenommen (siehe
Abbildung 5).
Abbildung 5
Zuordnungen
mit Spaltenansicht
°
Objektbeziehungen ([email protected]:datimpobjectreferences): In dieser Liste
werden die Referenzen zwischen den am Import beteiligten Objekten definiert (siehe Abbildung 6).
4. Datenimportobjekt
33
Abbildung 6
Objektbeziehungen mit
Spaltenansicht
Suchen und Erzeugen von Objekten
°
Klasseneigenschaften ([email protected]:datimpclassproperties): Hier wird für jede
Objektklasse definiert, welche Methode zum Suchen von bereits existierenden Objekten verwendet wird und
ob neue Objekte erzeugt werden sollen (siehe Abbildung 7).
Abbildung 7
Kasseneigenschaften mit
Spaltenansicht
Einstellungen zur Verarbeitung
Die Einstellungen zur Verarbeitung umfassen die Auswahl eines Bereichs der Datensätze sowie die Anzahl der
parallelen Transaktionen und deren Größe, wie in Abbildung 8 dargestellt.
4. Datenimportobjekt
35
Abbildung 8
Einstellungen und Optionen
des Datenimports
°
Anzahl der Datensätze für Commit ([email protected]:datimpbulksize) und Mindestens
([email protected]:datimpminbulksize): Mit diesen beiden Eigenschaften wird festgelegt,
wie viele Datensätze in einem Block verarbeitet und damit in einer Transaktion auf die Datenbank geschrieben werden.
°
Anzahl von Threads ([email protected]:datimpthreads): Diese Eigenschaft definiert die
Anzahl der in einem Datenimport verwendeten parallelen Worker Threads.
°
Anfangsdatensatz ([email protected]:datimpstartrecord) und Anzahl zu lesender
Datensätze ([email protected]:datimprecords): Mit diesen beiden Eigenschaften wird der
Bereich der zu verarbeiteten Datensätze angegeben.
Protokollierungsoptionen
Die Protokollierungsoptionen sind in Abbildung 9 dargestellt.
Abbildung 9
Protokollobjekt
°
Protokollmodus ([email protected]:datimprecordmode): Diese Eigenschaft bestimmt den
Detaillierungsgrad des Protokolls.
°
Protokoll-Objekt ([email protected]:datimplogobj): In dieser Eigenschaft wird jenes Objekt
abgelegt, in dem die Protokolle der Datenimporte gespeichert werden. Im Protokollobjekt wird pro Ladevorgang ein Eintrag erstellt, in dem neben Start- und Endzeit in einer Datei je nach Protokollmodus eine mehr
oder weniger ausführliche XML-Datei abgelegt wird. Ergänzt wird der Protokolleintrag durch die wichtigsten statistischen Daten wie Anzahl der Datensätze, Anzahl der erzeugten bzw. aktualisierten Objekte,
Anzahl der aufgetretenen Fehler und Anzahl der verwendeten Worker Threads.
4. Datenimportobjekt
37
°
Maximale Anzahl der Einträge im Protokoll ([email protected]:datimpmaxhistory): Wird
dieser Wert gesetzt, wird im Protokollobjekt maximal die gesetzte Anzahl von Protokolleinträgen aufbewahrt, um den Aufwand für die Protokollierung in Grenzen zu halten.
Performanceoptionen
Zuletzt sind in Abbildung 8 noch vier vor allem für die Performance relevante Eigenschaften des Datenimportobjekts zu sehen.
°
Änderungen sofort anzeigen ([email protected]:datimpuiupdate): Wird diese Eigenschaft
auf den Wert „Ja“ gesetzt, so werden im Fabasoft Win32-Client der Version 6 die Änderungen an den Objekten im Rahmen des Commits der Transaktion an die Benutzerschnittstelle weitergegeben. Damit werden die
Objekte sofort aktualisiert.
°
Methoden ohne Prüfung übergehen? ([email protected]:datimpfastwrapper): Wird konfiguriert, dass Methoden übergangen werden sollen und ist diese Eigenschaft auf „Ja“ gesetzt, wird beim
Übergehen nicht geprüft, ob die Methode gerade auf die konfigurierte Objektklasse bzw. Eigenschaft angewendet wird.
°
Datenimport bei Fehler sofort abbrechen ([email protected]:datimtermonerror): Wird
diese Eigenschaft auf „Ja“ gesetzt, wird der Datenimport beim Auftreten des ersten Fehlers abgebrochen.
°
Objekte nicht aktualisieren ([email protected]:datimpnoobjectrefresh): Bei bereits
existierenden Objekten wird vor jeder Verwendung geprüft, ob dieses Objekt zwischenzeitlich von einem
anderen Fabasoft Components Kernel verändert wurde. Diese Prüfung entfällt, wenn diese Eigenschaft auf
„Ja“ gesetzt wird.
Skripts
Es gibt drei Skripts, die in verschiedenen Phasen der Verarbeitung jedes Datensatzes aufgerufen werden und
somit unterschiedliche Möglichkeiten bieten, in die Verarbeitung einzugreifen. Jedes dieser Skripts wird mit
einer eigenen booleschen Eigenschaft aktiviert bzw. deaktiviert (siehe Abbildung 10).
Abbildung 10
Skripts des Datenimports
°
Filter-Skript für Rohdaten ([email protected]:datimpfilterdata): In diesem Skript können
die Daten, die von der Datenquelle geliefert werden, vor der weiteren Verarbeitung noch gefiltert und modifiziert werden. Auch selbst definierte Spalten, die nicht von der Datenquelle stammen, können hier berechnet werden.
°
Filter-Skript für Objekte ([email protected]:datimpfilterobjects): Dieses Skript wird
nach dem Setzen der Eigenschaften und vor dem Aufruf der Commit-Methode aufgerufen.
4. Datenimportobjekt
4.1 Datenquellen
°
4.1
Filter-Skript für Objekte nach dem Commit ([email protected]:datimpfiltercommit):
Nach dem erfolgreichen Commit wird dieses Skript für jeden Datensatz aufgerufen.
Datenquellen
Die Quelldaten des Imports stammen meistens aus Datenbanken oder strukturierten Dateien (z.B. CSV-Dateien),
aber es können auch andere Datenquellen angebunden werden. Eine genaue Beschreibung der Datenquellen
und deren Konfiguration finden Sie im Kapitel „Konfiguration der Datenquellen“ auf Seite 131.
Auswahl des Datenbereichs
Von den Datensätzen, die von der Datenquelle geliefert werden, müssen nicht alle verarbeitet werden. Einerseits können im Skript für Rohdaten gezielt Daten herausgefiltert werden, andererseits besteht die Möglichkeit
nur einen bestimmten Bereich zu laden. Dazu gibt man die Nummer des ersten Datensatzes und die Anzahl der
zu lesenden Datensätze an. Damit kann man zum Beispiel zum Testen erst einmal wenige Datensätze importieren und danach die restlichen Datensätze. Oder man verwendet diese Funktion zur Aufteilung der Daten in verschiedene Datenblöcke, die dann mit mehreren Clients parallel importiert werden können.
Allerdings sollte man beachten, dass nicht immer gewährleistet ist, dass die Datensätze immer in derselben Reihenfolge geliefert werden, auch wenn das im Normalfall so ist. Gerade bei Datenbanken ist das nicht garantiert,
wenn auch die Reihenfolge meistens von der physikalischen Speicherung der Datensätze auf der jeweiligen
Datenbank abhängt. So werden Tabellen vom Microsoft SQL Server generell in der Reihenfolge gelesen, die dem
Clustered Index entspricht, sofern einer definiert ist. Gewissheit schafft in diesem Fall nur ein ORDER BY in
der SQL-Abfrage.
Bei anderen Datenquellen (z.B. CSV-Dateien) ist die Reihenfolge durch die Reihenfolge der Datensätze am Medium gegeben und somit können gezielt Datenbereiche ausgewählt werden.
39
4.2
objektklassen
In den folgenden Kapiteln werden Objektklassen zur Identifikation von Objektmengen verwendet. So werden
Zuordnungen von Werten zu Eigenschaften von Objekten durch die Angabe der Objektklasse und der Eigenschaft
definiert. Die Objektklasse ist aber in einigen Fällen nicht ausreichend, um die Objektmenge eindeutig zu identifizieren, da Objektklassen in einem Datenimport auch in unterschiedlichen Funktionen verwendet werden können. Zum Beispiel werden bei der Definition von Hierarchien eine übergeordnete Instanz und eine untergeordnete Instanz derselben Objektklasse verwendet. Um diese Instanzen unterscheiden zu können, wird überall
neben der Objektlasse auch noch eine numerische Objekt-ID angegeben. Die Kombination von Objektklasse und
ID identifiziert dann das Objekt in seiner Funktion.
Die ID kann pro Objektklasse unabhängig vergeben werden. Ist keine ID angegeben, so wird sie implizit als „0“
interpretiert.
Für jede Objektklasse kann für jede ID explizit angegeben werden, ob neue Objekte angelegt werden sollen und
ob die Objekte gesperrt werden sollen.
Die Suchmethoden, Suchbereiche und Optionen wirken sich auf alle Instanzen der Objektklasse aus, egal welche ID verwendet wird. Auch die Definition der Schlüsseleigenschaften muss pro Objektklasse einheitlich erfolgen.
4.3
Setzen und Ändern von Eigenschaften
Eigenschaften
In diesem Bereich des Datenimportobjekts wird spezifiziert, welche Spalten der Datenquelle in der Fabasoft
Components Domäne Eigenschaften von Objekten zugeordnet werden.
4. Datenimportobjekt
4.2 Objektklassen
4.3 Setzen und Ändern von Eigenschaften
Beispiel: Zuordnung der Schlüsseleigenschaft einer Person
Es sollen die Werte der Spalte CustomerID der Eigenschaft Externer Schlüssel
([email protected]:objexternalkey) der Objektklasse Person ([email protected]:
CISPerson) zugeordnet werden. Diese Zuordnung ist in Abbildung 5 in der Spaltenansicht dargestellt.
Eine Spalte der Quelldaten kann auch mehreren Eigenschaften – auch verschiedener Objektklassen – zugeordnet werden. Dazu verwendet man einfach den Namen der Spalte in mehreren Zeilen der Zuordnungstabelle.
Soll eine Eigenschaft auf einen Festwert gesetzt werden, so kann an Stelle des Spaltennamens in der Eigenschaft Spalte in der Eigenschaft Festwert jener Wert eingetragen werden, der der Eigenschaft zugeordnet werden soll.
Werte können auch aus mehreren Spalten und Festwerten zusammengesetzt werden. Dazu werden einfach
mehrere Zuordnungen zur selben Objektklasse und Eigenschaft definiert und alle dadurch zusammengesetzten
Werte werden als Zeichenkette aneinandergehängt. So kann beispielsweise der Objektname der Person aus
dem Nachnamen, einem Beistrich und dem Vornamen zusammengesetzt werden, indem zuerst für die Spalte
Nachname, dann für den Festwert „, “ und schließlich für die Spalte Vorname eine Zuordnung zur selben
Eigenschaft des Objektes erstellt wird. Eine Zeile, in der weder eine Spalte noch ein Festwert enthalten sind,
wird als Festwert mit einem Leerzeichen interpretiert. Da die Werte intern immer als Zeichenketten vorliegen,
werden sie auch immer als Zeichenketten zusammengefügt, ganz egal ob sie einer Zeichenketteneigenschaft
oder zum Beispiel einer Zahleneigenschaft zugeordnet werden.
Für komplexere Formatierungen muss auf SQL- bzw. Rohdatenskripts zurückgegriffen werden. Dafür steht auch
die Möglichkeit zur Verfügung, berechnete Spalten zu verwenden. Diese werden bei der Zuordnung wie Spalten der Datenquelle behandelt, erhalten aber ihren Wert vom Rohdatenskript, das später beschrieben wird. Zur
Unterscheidung von Datenbankspalten beginnen die Namen dieser Spalten mit einem „@“-Zeichen.
41
Objektbeziehungen
In einem Datensatz werden neben einzelnen Objekten (z.B. Personen) auch Beziehungen zwischen Objekten definiert. So sind bei Personen auch oft Zuordnungen zu Organisationen oder Firmen hinterlegt, die in eigenen Objekten erfasst sind. Um diese Verbindung herzustellen, werden bei den Eigenschaften Zuordnungen zu mehreren
Objektklassen definiert. Um diese miteinander zu verknüpfen, definiert man bei den Objektbeziehungen, welches
Quellobjekt in die angegebene Objektzeiger-Eigenschaft des Zielobjektes übernommen werden soll.
Beispiel: Objektbeziehung zwischen Person und Organisation
In Abbildung 6 wird die Objektbeziehung zwischen Organisation und Person definiert, indem die Objektklasse in die Eigenschaft Organisation ([email protected]) der zusammengesetzten Eigenschaft Organisation ([email protected]:persjobs) eingetragen wird. Durch die
Rückwärtsverkettung wird auch die Person in der Eigenschaft Personen ([email protected]:
orgemployeelist) der Organisation eingetragen. Diese Zuordnung kann optional auch direkt im
Datenimportobjekt durch eine weitere Objektbeziehung abgebildet werden, was aber praktisch keinen Vorteil hat.
Auch hier können Objekte gleichzeitig in mehrere Eigenschaften derselben oder anderer Objektklassen eingetragen werden, man muss nur das Quellobjekt in mehreren Zeilen als Quellobjekt eintragen. Auch ist es möglich,
gleichzeitig mehrere Objekte in eine Objektliste einzufügen, indem man die Zielobjektklasse und Eigenschaft in
mehreren Zeilen verwendet. Auch können Objekte in einem Ladevorgang als Quell- und Zielobjekt in einer oder
mehreren Zeilen verwendet werden.
Schlüsseleigenschaften und Änderung von Werten
Die Art und Weise der Änderung kann bei Zuordnung von Werten zu Eigenschaften mithilfe der Eigenschaft
Schlüssel- und Änderungsmodus konfiguriert werden, bei den Objektbeziehungen mithilfe der Eigenschaft
Änderungsmodus. Die unterschiedliche Bezeichnung ergibt sich nur aus der Tatsache, dass Objektzeigereigen-
4. Datenimportobjekt
4.3 Setzen und Ändern von Eigenschaften
schaften keine Schlüsseleigenschaften sein können. Abbildung 11 zeigt die möglichen Werte der Eigenschaft im
Rahmen der Zuordnungen.
Abbildung 11
Schlüssel und
Änderungsmodus
Schlüssel
Schlüsseleigenschaften identifizieren ein Objekt eindeutig, wobei ein Objekt durch eine oder mehrere Eigenschaften identifiziert werden kann. Mindestens eine dieser Eigenschaften muss einen Wert beinhalten, um
einen gültigen Schlüssel zu ergeben. Objekte, die keinen gültigen Schlüssel haben, bei denen also keine der definierten Schlüsseleigenschaften einen Wert zugeordnet hat, der nicht leer ist, werden weder gesucht noch
erzeugt.
Bei der Suche nach bestehenden Objektinstanzen werden die Schlüsseleigenschaften als Suchkriterien verwendet. Wird das Objekt nicht gefunden, so kann eine neue Instanz angelegt werden und dieser werden die Schlüs-
43
seleigenschaften zugewiesen, sodass sie in weiterer Folge unter diesem Schlüssel wiedergefunden werden
kann. Daher können diese Eigenschaften auch nicht mehr verändert werden. Es gibt Einschränkungen, welche
Eigenschaften als Schlüsseleigenschaften verwendet werden können. Darauf wird später noch eingegangen.
Objektbeziehungen gehören nicht dazu und daher ist dieser Änderungsmodus bei Objektbeziehungen auch nicht
auswählbar.
Setzen beim Erzeugen
Wie bei Schlüsseleigenschaften wird die Eigenschaft nur dann gesetzt, wenn das Objekt während der Verarbeitung dieses Datensatzes erzeugt wurde. Werte bestehender Objekte werden nicht mehr verändert. Ist für diese
Eigenschaft ein Defaultwert definiert oder wird diese durch einen Konstruktor gesetzt, bleibt dieser Wert erhalten, sofern der Wert der zugeordneten Spalte leer ist. Das ergibt sich daher, dass Leerwerte bei diesem Modus
nicht gesetzt werden, um unnötige Aktualisierungen zu vermeiden.
Ändern
Die Eigenschaft wird geändert, wenn die zugeordnete Spalte einen Wert beinhaltet. Bestehende Werte werden
also durch Leerwerte nicht überschrieben. Bei Listeneigenschaften werden die Werte an die Liste angefügt, ausgenommen es ist eine Liste mit eindeutigen Einträgen und der Wert ist bereits in der Liste enthalten. Das wird
im Typ der Eigenschaft durch die Eigenschaft Eindeutige Einträge in Liste bestimmt. Dazu wird der Wert der
Eigenschaft ausgelesen. Nur wenn dieser ungleich dem neuen Wert ist bzw. bei eindeutigen Listen der neue
Wert in der Liste noch nicht enthalten ist, wird der Wert geändert. Beim nochmaligen Laden der Daten werden
dadurch nur die notwendigen Änderungen der Eigenschaften durchgeführt, aber keine Duplikate eingefügt. Ein
Problem ergibt sich jedoch bei Eigenschaften, deren Werte durch Get- oder Set-Aktionen geändert (z.B. formatiert) werden. Diese werden als ungleich erkannt und jedes Mal aufs Neue geändert.
4. Datenimportobjekt
4.3 Setzen und Ändern von Eigenschaften
Überschreiben
Die Eigenschaft wird geändert, auch wenn der Wert der zugeordneten Spalte leer ist. In diesem Fall wird die
Eigenschaft also gelöscht. Auch hier wird der Wert nur gesetzt, wenn er sich gegenüber dem bestehenden Wert
geändert hat.
Bei Listeneigenschaften wird der gesamte Inhalt der Liste durch den vorliegenden Wert ersetzt bzw. gelöscht,
wenn der Eigenschaft kein Wert zugewiesen wird. Ist dafür keine Änderung notwendig, wird die Eigenschaft
nicht neu gesetzt.
Löschen und neu anlegen
Dieser Änderungsmodus dient zum Abgleich bestehender Listen durch eine Datenquelle (z.B. dem Active Directory). Es werden dabei alle Werte der Eigenschaft gelöscht und durch die Werte aus dem Datenimport neu
befüllt.
Beispiel: Abgleich der Gruppen eines Benutzers über LDAP
Wenn man die Benutzerdaten mit einer LDAP-Datenquelle abgleicht, so werden den Benutzern in der Regel
Gruppen zugeordnet. Problematisch ist dabei das Löschen von Gruppenzuordnungen, da für diese Löschung
von der Datenquelle kein Datensatz geliefert wird, sondern nur jene Datensätze für die aktiven Zuordnungen in den Quelldaten enthalten sind. Daher muss die Zuordnungstabelle bei jedem Ladevorgang komplett
neu aufgebaut werden.
Dabei muss jedoch sichergestellt werden, dass der komplette Neuaufbau der Liste innerhalb der Verarbeitung
eines einzigen Datenblocks durchgeführt wird, da sonst bei der Verarbeitung des nächsten Datenblocks die gerade gesetzten Werte gelöscht würden. Das kann durch Sortierung der Daten im Zusammenhang mit der Verwendung der Option „Gruppenwechsel“ gewährleistet werden.
Diese Option ist nur bei Listeneigenschaften auf Objektebene verwendbar. Listeneigenschaften innerhalb
zusammengesetzter Eigenschaften können mit dieser Methode nicht abgeglichen werden.
45
Ignorieren
Diese Option dient dazu, Zuordnungen zu deaktivieren. Allerdings wird dadurch nur die Zuordnung des Wertes
bzw. des Objektzeigers zur Eigenschaft deaktiviert und daher werden keine Änderungen mehr durch diese Zeilen verursacht. Nicht deaktiviert werden einige später noch beschriebene Optionen. Sie bleiben trotz „Ignorieren“ wirksam. Auf diese Spezialfälle wird dann im Rahmen der Behandlung zusammengesetzter Eigenschaften
und dem Übergehen von Methoden näher eingegangen.
Setzen von Inhaltseigenschaften
Das Setzen von Inhaltseigenschaften erfolgt, wie bei anderen Eigenschaften auch, durch Zuordnung eines
Werts zu der Inhaltseigenschaft. Damit ist nicht etwa die zusammengesetzte Eigenschaft Hauptinhalt
([email protected]:content) gemeint, sondern Eigenschaften mit dem Typ Inhalt
([email protected]: CONTENT) oder Liste von Inhalten ([email protected]:CONTENTLIST). Es
gibt dabei zwei mögliche Interpretationen des Werts, einerseits als Dateiname und andererseits als Wert.
Wenn nicht anders angegeben, wird zuerst versucht den zugeordneten Wert als Dateinamen zu interpretieren.
Wenn es unter dem angegebenen Pfad eine Datei gibt, wird diese mit SetFile der Inhaltseigenschaft zugeordnet. Gibt es an der angegebenen Stelle keine Datei, so wird der Wert in eine temporäre Datei geschrieben
(im ANSI-Zeichensatz) und der Inhaltseigenschaft zugewiesen. Diese temporäre Datei wird dabei vom Datenimport automatisch wieder gelöscht. Werden Dateien von der Datenquelle in eine temporäre Datei geschrieben,
werden diese Dateien ebenfalls nach der Verarbeitung wieder gelöscht.
Dieses Verhalten kann man durch Optionen, die man bei der Zuordnung angibt, modifizieren. Gibt man die
Option „Dateiname“ an, so wird der Wert immer als Dateiname interpretiert. Ist an der angegebenen Stelle
keine Datei zu finden, dann wird die Eigenschaft nicht gesetzt. Gibt man jedoch die Option „Inhalt als Wert“ an,
so wird nicht versucht eine Datei zu finden, sondern der Wert wird über den Umweg einer temporären Datei der
Inhaltseigenschaft zugewiesen.
Diese Optionen haben auch Auswirkungen auf die Art, wie die Daten von der Datenquelle geholt werden.
Sowohl bei OLE DB- als auch bei ODBC-Datenquellen werden Werte, deren Größe 4.000 Zeichen überschreitet,
4. Datenimportobjekt
4.3 Setzen und Ändern von Eigenschaften
temporär als Datei abgelegt, da diese meistens Inhaltseigenschaften zugeordnet werden. Diese Dateien können
beliebige Länge haben und sie werden binär von der Datenquelle gelesen und in die Datei geschrieben. Verwendet man bei OLE DB-Datenquellen die Option „Inhalt als Wert“, so wird der Wert nicht in einer Datei abgelegt
und der Wert – maximal jedoch 500 Kilobyte – als Wert übergeben. Damit können vor allem auch längere Stringlisten auf einmal mit Werten befüllt werden.
Aus Gründen der Performance werden Inhaltseigenschaften nicht mit bestehenden Inhalten verglichen, um sie
nur bei Änderungen zu setzen, sondern sie werden immer neu gesetzt, je nachdem welcher Änderungsmodus
eingestellt ist. Um unnötige Änderungen auf den MMC-Bereichen zu vermeiden empfiehlt es sich daher, die
Inhalte nur dann zu setzten, wenn wirklich neue Inhalte darin enthalten sind. Gerade bei MMC-Bereichen mit
Logging würde sonst unnötig viel Speicherplatz belegt, der erst bei einem Aufräumen wieder freigegeben
würde. In Migrationen kann man durch den Änderungsmodus „Setzen beim Erzeugen“ oft den gewünschten
Effekt erzielen, sodass zum Beispiel bei einem nochmaligen Start des Imports die Inhalte bereits bestehender
Inhaltsobjekte nicht nochmals gesetzt werden.
Inhalte im Archiv
Eine sehr effiziente Art Inhalte zu „importieren“ bietet sich im Zusammenhang mit Archivsystemen. Anstatt die
Inhalte vom Client auf die Fabasoft Components MMC-Services zu übertragen und dort im Dateisystem abzulegen, werden jene Daten importiert, die die Verbindung von einem Objekt zu einem bereits existierenden Inhalt
auf einem Archivsystem darstellen, also quasi nur ein Link auf die eigentlichen Daten. Dadurch müssen die Inhalte nicht mehr während der Migration bewegt werden, sondern können im Vorhinein im Archiv erfasst werden. Die Daten werden dann zur Migration nur mehr über Referenzen eingebunden. Jede Referenz auf einen
Inhalt des Archivsystems besteht aus einer Dokumenten-ID und einer Inhalts-ID. Beim Setzen des Inhalts
müssen diese beiden IDs gleichzeitig an den Fabasoft Components Kernel übergeben werden, der diese im
Objekt hinterlegt und damit die Referenz auf das Archivsystem aufbaut. Wird später auf den Inhalt zugegriffen,
erkennt der Fabasoft Components Kernel aufgrund dieser Informationen, dass der Inhalt im Archiv liegt und findet ihn unter der angegeben Dokumenten- und Inhalts-ID. Um die Referenz im Datenimport zu konfigurieren,
steht die Eigenschaft Archivposition zur Verfügung. Drei Werte spielen hierbei eine Rolle:
47
Das Archivstore-Objekt, das das Archiv definiert, in dem der Inhalt archiviert wurde, wird direkt in die Eigenschaft Archivstore in der Archivposition eingetragen.
Die Dokumenten-ID wird durch die Zuordnung auf die Inhaltseigenschaft definiert.
Für die ID des Inhaltes wird ein zweiter variabler Wert benötigt, der aus jener Spalte genommen wird, deren
Name in der Archivposition unter Spalte mit ID des Inhalts hinterlegt ist.
Mit dieser Methode kann ein Import von Inhaltsobjekten erfolgen, ohne einen einzigen Inhalt zum Zeitpunkt der
Migration transferieren zu müssen. Trotz dieses Vorteils habe ich seit 1999 keine Migration betreut, in der diese Vorgehensweise gewählt wurde. Bei einigen Migrationen wurden aber Teile der Datenbestände bereits im
Rahmen der Migration oder in einer anschließenden Phase auf Archive ausgelagert. Wie das geht, wird bei den
Anwendungsfällen der Skripts näher erläutert.
Zeichenkettenlisten
Zeichenkettenlisten sind einerseits ganz normale Listen von einzelnen Zeichenketten, wie sie zum Beispiel in der
Eigenschaft Log-in-Name ([email protected]:userlogname) der Objektklasse Benutzer verwendet
werden. Dort werden die Log-in-Namen des Benutzers – jeder Log-in in einer eigenen Zeile – abgelegt. Andererseits können die Zeichenkettenlisten auch wie eine Inhaltseigenschaft interpretiert und als Text bearbeitet
werden. Dafür steht auch im Datenbankschema der Fabasoft Components COO-Services die Möglichkeit zur Verfügung, diese Zeichenkettenlisten in einer Textspalte mit 4.000 Zeichen abzulegen. Verwendet man diese datenbankseitige Abbildung nicht, so können Zeichenkettenlisten theoretisch beliebig groß werden. Weist man in
einem Datenimport einer Zeichenkettenliste Werte zu, so erhält man im Grunde dasselbe Verhalten, wie bei
anderen Listeneigenschaften. Man kann also den Wert auch zeilenweise zur Zeichenkettenliste hinzufügen.
Beinhaltet der Wert jedoch mehrere Zeilen, werden alle diese Zeilen der Eigenschaft zugewiesen. Damit kann
man mit einem Datensatz ganze Texte in Zeichenkettenlisten setzten.
Hier kommt jedoch das Limit der ODBC- und OLE DB-Datenquellen wieder zum Tragen, die bei Spalten, die länger als 4.000 Zeichen sind, alle Inhalte (egal wie groß die enthaltenen Daten sind) in Dateien ablegen. Überschreitet eine Spalte der Datenquelle dieses Limit, so wird man an Stelle des Wertes einen Dateipfad auf eine
4. Datenimportobjekt
4.3 Setzen und Ändern von Eigenschaften
temporäre Datei in der Eigenschaft vorfinden, die im Rahmen des Datenimports wieder gelöscht wurde. Das
kann man im Fall von OLE DB- und seit Neuem auch bei ADE DB-Datenquellen verhindern, indem man die
Option „Inhalt als Wert“ in der Zeile, in der diese Datenbankspalte steht, angibt. Damit können Werte bis maximal 500 Kilobyte als Text in der jeweilige Spalte verarbeitet und so in eine Zeichenkettenliste geladen werden.
Daten, die über die 500-Kilobyte-Grenze hinausgehen, werden dabei jedoch ohne Fehlermeldung abgeschnitten.
Bei allen anderen Datenquellen ändert die Option nichts am Verhalten der Datenquelle.
Bis Fabasoft Components Version 5.0.2 mussten Zeichenkettenlisten in Listen von Zeichenketten zerlegt werden.
Dazu musste die Option „Zeichenkettenliste“ angegeben werden. Es wurde dabei erstens bei Zeilenumbrüchen
(CR, LF oder CRLF), zweitens beim letzten Leerzeichen vor der in der Eigenschaft definierten maximalen Länge der Zeichenkette und drittens, falls kein Leerzeichen bis zu dieser Marke enthalten war, genau bei dieser Länge umgebrochen.
Ab Version 5.0.3 muss der Wert der Zeichenkettenliste nicht mehr zerlegt werden, da der Fabasoft Components
Kernel das selbständig erledigt und auch Zeilen mit einer Länge unterstützt, die größer ist als die maximal eingestellte Zeichenlänge.
Zusammengesetzte Eigenschaften
Wie bereits erwähnt werden Eigenschaften in zusammengesetzten Eigenschaften (in den Referenzen und in
manchen Bezeichnungen findet sich dafür auch noch die frühere Bezeichnung Aggregat) durch den Eigenschaftspfad definiert, also durch die vollständige Liste aller Eigenschaften, die vom Objekt bis zum konkreten
Wert führen.
49
Beispiel: Eigenschaftspfad bei Telefonnummerneigenschaft
Die Eigenschaft Telefonnummern ([email protected]:telephones) ist eine zusammengesetzte
Eigenschaft, die bis zu vier Werte beinhalten kann:
°
°
°
°
Typ ([email protected]:teltype)
Telefonnummer ([email protected]:telnumber)
Beschreibung ([email protected]:teldesc)
Telefonnummer (Rohformat) ([email protected]:rawnumber)
Um eine Telefonnummer in die Telefonnummern-Eigenschaft zu setzen, muss also als Eigenschaftspfad
Telefonnummern.Telefonnummer ([email protected]:[email protected]:
telnumber) eingetragen werden.
Analog verfährt man mit dem Typ der Telefonnummer ([email protected]:
[email protected]:teltype) der in unserem Beispiel mit einem Festwert belegt
wird (siehe Abbildung 1).
Innerhalb einer Funktion (Kombination von Objektklasse und Objekt-ID) beziehen sich gleiche Attributspfade
auch immer auf die gleichen Zeilen in einer Liste. Also ist auch hier sichergestellt, dass sich der Typ und die Telefonnummer auf dieselbe Zeile der Liste der Telefonnummern-Eigenschaften beziehen. Zusammengesetzte Eigenschaften werden befüllt, wenn zumindest einer Eigenschaft ein Wert zugewiesen wird. In unserem Beispiel mit
den Telefonnummern wird dem Typ immer der konstante Wert „400“ zugewiesen. Damit wird die Telefonnummern-Eigenschaft prinzipiell immer gesetzt, egal ob in den Quelldaten eine Telefonnummer angegeben ist oder
nicht. Daher gibt es die Option „Muss im Aggregat definiert sein“, die bei jener Eigenschaft gesetzt wird, ohne
die der Eintrag nicht sinnvoll ist, und sicherstellt, dass eine zusammengesetzte Eigenschaft nur dann angelegt
wird, wenn alle Werte, die definiert sein müssen, auch wirklich definiert sind.
4. Datenimportobjekt
4.3 Setzen und Ändern von Eigenschaften
Hintergrund: Berücksichtigung von Muss-Eigenschaften
Im Datenimport wird die Information aus dem Datenmodell, ob eine Eigenschaft gesetzt werden muss oder
nicht, generell nicht beachtet. Diese Information wird normalerweise im Rahmen der Darstellung in der
Benutzerschnittstelle verwendet, um unterschiedliche Darstellungen der Eigenschaften zu erreichen und
um Eingaben in bestimmte Eigenschaften zu erzwingen. Für das Datenmodell selbst hat diese Information
aber keine Bedeutung, es wird also nicht erzwungen, dass in einer Muss-Eigenschaft ein Wert enthalten
ist, bevor eine Transaktion abgeschlossen wird. Aber selbst für die Darstellung in der Benutzerschnittstelle kann diese Information überschrieben werden, um in einer konkreten Installation ein anderes Verhalten
zu erreichen. Daher kann sich der Datenimport nicht auf diese Information verlassen und sie wird ignoriert.
Als Ersatz dafür wurde bei zusammengesetzten Eigenschaften die Option „Muss im Aggregat definiert
sein“ eingeführt, um unvollständig definierte Einträge in zusammengesetzten Eigenschaften zu verhindern.
Verarbeitung von Listen
Das Laden von Listeneigenschaften stellt immer wieder eine Herausforderung dar, da einige Randbedingungen
beachtet werden müssen.
Mehrere Einträge pro Datensatz
Ein typisches Beispiel für einen Datensatz, in dem mehrere Einträge enthalten sind, die auf mehrere Zeilen in
einer Liste abgebildet werden, sind Telefonnummern und Faxnummer von Personen oder Organisationen. Im
Objektmodell sind diese Nummern als Liste von zusammengesetzten Eigenschaften abgebildet, die neben der
Nummer auch noch die Art der Nummer (Typ) beinhaltet, also zum Beispiel ob diese Nummer eine Mobiltelefonnummer, eine Büronummer oder eine Faxnummer ist. In den Quelldaten hat man aber oft in einem einzigen
Datensatz zwei oder mehr Spalten mit Telefonnummern und die die Art der Telefonnummer (z.B. „OfficePhone“,
„MobilePhone“, „Fax“) wird durch die Spaltenbezeichnung definiert.
51
Nehmen wir an, drei Telefonnummern sollen auf drei Zeilen in der Liste Telefonnummern
([email protected]:telephones) abgebildet werden. Wie im letzten Abschnitt besprochen, wird die
Spalte OfficePhone dem Eigenschaftspfad Telefonnummern.Telefonnummer ([email protected]:
[email protected]:telnumber) zugeordnet und der Fixwert „400“ für den Typ „Büro“
in der Eigenschaft Telefonnummern.Typ ([email protected]:[email protected]:
telnumber) gesetzt. Um die Zeile der Mobiltelefonnummer und der Faxnummer von dieser Zeile unterscheiden zu können, wird auf die anfangs erwähnten Objekt-IDs zurückgegriffen. Wir definieren also quasi eine Person in der Funktion „Person mit Büro-Telefonnummer“, eine weitere mit der Funktion „Person mit Mobiltelefonnummer“ und eine dritte mit der Funktion „Person mit Faxnummer“, also jede mit einer unterschiedlichen ObjektID. Dass es sich dabei eigentlich um dieselbe Person handelt kann man dadurch ausdrücken, dass alle diese Personen dieselben Schlüsselwerte verwenden. Noch eleganter ist es, wenn man die Objekt-IDs aufsteigend vergibt und bei den Personen mit der zweiten und dritten Funktion als Methode zur Vermeidung doppelter
Objekte den Eintrag „Verwende das selbe Objekt mit niedrigerer Objekt-ID“ auswählt. Damit muss man nur
mehr bei der ersten Funktion die Schlüsseleigenschaften angeben und die geeignete Suchmethode auswählen.
Die Objekte der Personen mit den anderen Funktionen sind implizit bekannt und man muss nur mehr, wie in
Abbildung 12 zu sehen, die zu setzenden Eigenschaften zuordnen.
4. Datenimportobjekt
4.3 Setzen und Ändern von Eigenschaften
Abbildung 12
Definition mehrerer Listeneinträge pro Datensatz
Eindeutige Einträge in Liste
In vielen Fällen ist es gewünscht, dass in Listen keine doppelten Einträge geladen werden sollen. Das hat auch
für den Import große Vorteile. Zum Beispiel vermeidet man damit, selbst wenn ein Import teilweise wiederholt
werden muss, dass unerwünschte Einträge in den Listen entstehen. Sind Listen vom Objektmodell her durch das
Setzen der Eigenschaft Eindeutige Einträge in Liste des Eigenschaftstyps so definiert, wird diese Einschränkung automatisch vom Datenimport berücksichtigt. Es gibt aber auch Situationen, in denen im Objektmodell
Duplikate erlaubt sind, im Datenimport jedoch keine Duplikate eingefügt werden sollen. Dafür gibt es die
Option „Eindeutige Einträge in Liste“, die in jener Zeile der Zuordnungen oder Objektbeziehungen definiert wird,
in der diese Eigenschaft gesetzt wird.
53
Etwas komplizierter ist das bei Listen zusammengesetzter Eigenschaften. Hier kann neben der Tatsache, dass es
sich um eine Liste mit eindeutigen Einträgen handelt, auch noch angegeben werden, welche Eigenschaften zum
Vergleich herangezogen werden, welche Eigenschaften also die Schlüsseleigenschaften der Listeneinträge sind.
Auch diese können bei zusammengesetzten Eigenschaften bereits im Objektmodell, im Typ der Eigenschaft, in
der Eigenschaft Schlüssel für eindeutige Listen ([email protected]:typeuniqueattrs) vorgegeben sein. Ist das nicht der Fall oder sollen andere Eigenschaften zum Vergleich herangezogen werden, so kann
man bei den entsprechenden Zuordnungen durch Setzten der Option „Aggregatsschlüssel“ definieren, welche
Eigenschaften zum Vergleich mit anderen Einträgen der Liste herangezogen werden sollen. Wenn also angenommen beim Import der Typ der Telefonnummern eindeutig sein soll, also jede Person maximal eine Büronummer,
eine Mobiltelefonnummer und eine Faxnummer bekommen soll, dann muss bei jeder Zuordnung zum Typ der
Telefonnummer ([email protected]:[email protected]:teltype) die Option
„Aggregatsschlüssel“ gesetzt werden, um diese als Schlüsseleigenschaft innerhalb der Liste der zusammengesetzten Eigenschaft Telefonnummern ([email protected]:telephones) zu definieren.
Synchronisation von Listen
Bisher wurden Einträge immer nur in leere bzw. bereits bestehende Listen eingefügt. Beim regelmäßigem
Abgleich von Datenbeständen gibt es jedoch auch Situationen, in denen Einträge aus Listen entfernt werden
müssen. Wenn die zu löschenden Einträge in Datensätzen von der Datenquelle geliefert werden, dann kann das
Löschen über Skripts realisiert werden (siehe Kapitel „Zusätzliche Beispiele“ auf Seite 159). Eine andere Situation ergibt sich, wenn die Einträge nicht explizit gelöscht werden, sondern die aktuelle Liste einfach neu übertragen wird.
4. Datenimportobjekt
4.3 Setzen und Ändern von Eigenschaften
4.4 Identifikation und Duplikatsprüfung
Beispiel: Abgleich der Benutzergruppen über LDAP
Beim Abgleich der Benutzerinformationen aus LDAP-Quellen (z.B. Active Directory oder OpenLDAP) wird bei
Benutzern jedes Mal die komplette Liste der Gruppen übertragen, in denen der Benutzer enthalten ist.
Ändert sich die Zuordnung, so gibt es keine Information darüber, welche Zuordnung sich geändert hat. Nicht
mehr bestehende Zuordnungen sind einfach nicht mehr enthalten. Trotzdem sollen die Einträge in der Fabasoft Components Domäne gelöscht werden.
Beim Datenimport kann eine Liste über den Änderungsmodus „Löschen und neu anlegen“ neu befüllt werden.
Dazu wird der Inhalt der Eigenschaft am Beginn der Transaktion gelöscht und in weiterer Folge die Eigenschaften neu befüllt. Damit fallen alle Werte, die innerhalb der Transaktion nicht mehr eingetragen werden, automatisch aus der Liste heraus. Daraus ergibt sich aber auch eine Einschränkung dieser Option: Die Liste muss innerhalb einer einzigen Transaktion neu befüllt werden. Auch werden die Listen jedenfalls geändert, selbst wenn
sich die Werte im Endeffekt nicht verändern.
4.4
Identifikation und Duplikatsprüfung
Objektsuche
Der primäre Zweck der Klasseneigenschaften ist es, die Suche und das Erzeugen von Objekten zu steuern. Bisher war immer nur von Zuordnungen zu Objekten die Rede. Was aber, wenn zum Beispiel mehrere Personen derselben Organisation zugeordnet werden sollen? Dafür benötigt man einerseits eine oder mehrere Schlüsseleigenschaften, die ein Objekt innerhalb der Objektklasse eindeutig identifizieren, andererseits kann man konfigurieren, wie die Suche nach den Objekten ablaufen soll.
Schlüsseleigenschaften
Zur Definition der Schlüsseleigenschaften müssen wir noch einmal zu den Zuordnungen der Eigenschaften
zurückkehren. Dort gibt es nach dem Festwert eine Aufzählungseigenschaft Schlüssel- und Änderungs-
55
modus ([email protected]:datimpmapkeyupdate). Man macht eine Eigenschaft zu einer Schlüsseleigenschaft indem man den Schlüssel- und Änderungsmodus auf den Wert „Schlüssel“ setzt. Das
bewirkt automatisch, dass diese Eigenschaft zur Identifikation der Objekte genau dieser Objektklasse verwendet wird. Unterschiedliche Instanzen derselben Objektklasse, die sich nur durch die Objekt-ID unterscheiden,
müssen innerhalb eines Datenimports dieselben Schlüsseleigenschaften haben, da die Schlüsseleigenschaften
auch für die interne Verarbeitung verwendet werden. Unterschiedliche Objektklassen können durchaus auch
unterschiedliche Schlüsseleigenschaften haben. Zulässige Typen von Eigenschaften sind:
°
°
°
°
°
°
Zeichenketteneigenschaften
°
°
°
°
Keine Schlüsseleigenschaften können Listeneigenschaften sein, genauso wie
Zahleneigenschaften
Aufzählungseigenschaften
Boolesche Eigenschaften
Eigenschaften mit Datum und Zeit
Gleitkommazahleneigenschaften (diese sollten jedoch wegen der Rundungsproblematik nicht als Schlüssel
verwendet werden)
Eigenschaften mit Inhalt
Eigenschaften für Werte-Verzeichnisse
Objektzeigereigenschaften
Eigenschaften in zusammengesetzten Eigenschaften können Schlüsseleigenschaften sein, sofern die zusammengesetzte Eigenschaft nicht eine Liste ist und die Eigenschaft, die den Wert enthält, einen Eigenschaftstyp hat,
der eine Schlüsseleigenschaft sein kann und nicht mehrere Werte beinhalten kann.
4. Datenimportobjekt
4.4 Identifikation und Duplikatsprüfung
Suchen und Erzeugen von Objekten
Für jede Objektklasse kann man einstellen, wie die Objekte dieser Objektklasse im Zuge des Datenimports
gesucht werden sollen. Dabei stellt der Datenimport Grundmechanismen zur Verfügung, von denen einige Kombinationsmöglichkeiten auswählbar sind.
Diese Mechanismen sind:
°
°
Die Suche nach Objekten erfolgt über einzelne Suchabfragen in der Fabasoft Components Domäne.
°
°
Dieser Suchbaum kann durch eine Suche über alle Objekte der Objektklasse initialisiert werden.
In einem lokalen Suchbaum im Speicher der Anwendung („Cache“) wird zu jedem Objekt sein Schlüsselwert
gespeichert.
Die Suche nach Objekten erfolgt unter Verwendung der Hashtabelle der Objektklasse.
Daraus ergeben sich die in Abbildung 13 dargestellten Suchmethoden, die bei den Klasseneigenschaften in der
Eigenschaft Vermeidung doppelter Objekte auswählbar sind.
57
Abbildung 13
Methoden zur Vermeidung
doppelter Objekte
Keine Prüfung vorhandener Objekte
Die Objekte werden immer erzeugt, selbst wenn die Eigenschaft Erzeuge Objekte auf „Nein“ gesetzt wird.
Dazu wird keine Schlüsseleigenschaft benötigt. Wenn jedoch eine oder mehrere Schlüsseleigenschaften definiert sind, dann wird ein Objekt nur dann erzeugt, wenn mindestens einer dieser Eigenschaften ein Wert zugewiesen wird.
Vorteile:
°
°
Bei dieser Variante wird keine Suche durchgeführt, also ist diese Methode die schnellstmögliche.
Es wird kein Platz für den Suchbaum benötigt.
4. Datenimportobjekt
4.4 Identifikation und Duplikatsprüfung
Nachteile:
°
°
Durch die fehlende Suche können Objekte mehrfach geladen werden.
Die Fehlerbehandlung ist kompliziert, da durch eine Wiederholung des Ladevorgangs Duplikate entstehen.
Prüfung durch Sammeln von Schlüsseln für alle Objekte
In einer Initialisierungsphase wird ein lokaler Suchbaum (Cache) aufgebaut, in dem von allen Objekten der
Objektklasse die Schlüsselwerte und die Adresse des Objekts gespeichert werden. Während des Ladevorgangs
werden neu erzeugte Objekte in den Suchbaum eingetragen. Daher sind immer alle Objekte bekannt und es müssen keine weiteren Suchen erfolgen.
Vorteile:
°
Die Suche im lokalen Suchbaum ist in der Regel sehr schnell.
Nachteile:
°
°
Die Initialisierung des Suchbaumes kann lange dauern.
°
Durch die Parallelisierung bei der Initialisierung des Suchbaumes können Probleme auftreten, wenn Objekte vieler Objektklassen (mehr als drei) gesammelt werden.
Der Speicherverbrauch ist relativ hoch, da auch für Objekte, die vom Ladevorgang nicht betroffen sind, Speicher belegt wird. Der Einsatz dieser Suchmethode ist dadurch auf Objektklassen mit maximal einer Million
Instanzen beschränkt.
Diese Suchmethode wird also speziell dann verwendet, wenn ein großer Prozentsatz der bestehenden Daten
vom Ladevorgang betroffen ist, oder nur wenige Objekte bereits vorhanden sind. So kann die Anzahl der einzelnen Suchen reduziert werden. Der Aufwand der Initialisierung amortisiert sich bald.
59
Prüfung durch Suche für jedes Objekt
Bei dieser Suchmethode werden die Objekte bei der ersten Referenzierung über eine Suche in der Fabasoft Components Domäne gesucht. Bereits gefundene oder neu erzeugte Objekte werden im lokalen Suchbaum gespeichert, um bei mehrfacher Verwendung nicht noch einmal gesucht werden zu müssen.
Vorteile:
°
°
Es wird keine Initialisierungsphase benötigt.
Mehrfache Referenzierungen führen zu keinen weiteren Suchen.
Nachteile:
°
°
°
Die Suche pro Datensatz ist langsam.
Der Suchbaum benötigt für jedes verwendete Objekt Speicher.
Eine Optimierung der Suche auf der Datenbank ist notwendig.
Diese Suchmethode ist die Standardmethode, wenn für eine Objektklasse kein Eintrag in den Klasseneigenschaften angegeben ist.
Als Optimierung werden bei der Suche alle Objekte, die in einem Transaktionsblock verarbeitet werden, auf einmal gesucht, sofern bei der Objektklasse nur eine Schlüsseleigenschaft gesetzt ist.
Diese Suchmethode sollte speziell dann verwendet werden, wenn bereits viele Objekte in der Fabasoft
Components Domäne enthalten sind und nur wenige hinzukommen oder referenziert werden.
Prüfung durch Suche für jedes Objekt (kein Cache)
Speziell für den Fall, dass sehr viele Objekte geladen werden sollen, gibt es auch die Möglichkeit, den lokalen
Suchbaum auszuschalten. So wird vor allem das Speicherproblem des Suchbaumes umgangen.
4. Datenimportobjekt
4.4 Identifikation und Duplikatsprüfung
Vorteile:
°
°
Keine Initialisierungsphase
Minimaler Speicherverbrauch
Nachteile:
°
°
°
Langsame Suche pro Datensatz
Mehrfache Referenzen führen zu mehrfachen Suchen
Optimierung der Suche auf der Datenbank notwendig
Außer bei sehr großen Importen kann diese Methode auch effizient eingesetzt werden, wenn es keine oder nur
wenige mehrfache Referenzen auf Objekte gibt.
Prüfung durch Suche über Hashtabelle
Bei dieser – in konkreten Projekten kaum verwendeten – Methode wird direkt aus den Werten der Schlüsseleigenschaften ein Hashwert errechnet, aus dem die Objektadresse berechnet wird. Dazu muss zuvor in der
Fabasoft Components Domäne eine Hashtabelle für diese Objektklasse angelegt und ein ausreichender Bereich
von Objektadressen exklusiv für diese Hashtabelle reserviert werden. Die Objekte der Objektklasse müssen dann
immer über bestimmte Funktionen erzeugt werden, die als Parameter bereits die Schlüsselwerte des Objekts
enthalten. Diese können dann unter keinen Umständen geändert werden.
Vorteile:
°
Diese Variante ist in Spezialfällen effizient.
Nachteile:
°
Das Erzeugen von Objekten ist nur über einen Datenimport oder aus der Anwendungslogik heraus möglich,
da spezielle Funktionen zum Anlegen der Objekte verwendet werden müssen.
61
°
°
°
Die Anzahl der Objekte ist durch die Größe der Hashtabelle limitiert.
°
Die Schlüsseleigenschaften der Objekte dürfen nicht mehr geändert werden.
Durch die Kollisionsbehandlung ist das Anlegen von Objekte bei hohem Füllgrad der Hashtabelle ineffizient.
Die Hashtabelle muss während der Erzeugung von Objekten gesperrt werden und der Import kann daher
nicht sinnvoll parallelisiert werden.
Wegen dieser prinzipiellen Einschränkungen finden die Hashtabellen und damit auch die Suchmethode in
Fabasoft Components/COLD kaum Verwendung. Während der Initialisierungsphase des Datenimports wird für
jede Objektklasse geprüft, ob eine Hashtabelle definiert ist, um zu verhindern, dass Objekte von Objektklassen
mit Hashtabelle ohne Verwendung der Hashtabelle erzeugt werden.
Prüfung durch Suche im lokalen Cache
Diese Methode verwendet den lokalen Suchbaum, der jedoch nicht durch eine Initialisierung vorher befüllt wird.
Objekte die nicht bereits im Suchbaum enthalten sind, werden erzeugt und in den Suchbaum eingetragen.
Dadurch wird ein mehrfaches Erzeugen von Objekten in einem Ladevorgang verhindert.
Vorteile:
°
°
°
Es wird keine Initialisierung benötigt.
Es werden keine Suchen pro Datensatz durchgeführt.
Die Suchen im lokalen Suchbaum sind sehr schnell.
Nachteile:
°
°
Objekte, die bereits vorhanden waren, werden nicht gefunden.
Die Fehlerbehandlung ist kompliziert, da durch eine Wiederholung des Ladevorgangs Duplikate entstehen.
4. Datenimportobjekt
4.4 Identifikation und Duplikatsprüfung
Verwende das selbe Objekt mit niedrigerer Objekt-ID
Diese Methode ist nur im Zusammenhang mit einer anderen Suchmethode einsetzbar und ist somit die einzige
Variante, bei der in mehreren Instanzen einer Objektklasse unterschiedliche Methoden zur Vermeidung doppelter Objekte verwendet werden dürfen.
Die Anwendung wird im Rahmen der Behandlung von Listen besprochen.
Suche unter Verwendung der Objektadresse
Als Sonderfall kann man die Suche nach Objekten über die Objektadresse ansehen. Dafür definiert man bei den
Zuordnungen der Eigenschaft eine Spalte oder einen Festwert, der die Objektadresse (in der Form
„COO.<domain-major-id>.<domain-minor-id>.<store-id>.<object-id>“) enthält. Als Suchmethode wählt man
„Prüfung durch Suche für jedes Objekt“. Diese Variante ist besonders effizient, da auf das Objekt direkt über seine Adresse zugegriffen wird und keine Suchen benötigt werden. Sie eignet sich einerseits dafür, fixe Objekte
über konstante Werte zu hinterlegen, andererseits kann man damit auch sehr effiziente Optimierungen umsetzen, indem man Fremdschlüssel bereits auf der Datenquelle auflöst. Hat man beispielsweise durch einen Datenbankexport die Schlüsseleigenschaften und die Objektadresse aller referenzierten Objekte auf die Quelldatenbank exportiert, so kann man durch einen JOIN zwischen der Tabelle der Quelldaten und der exportierten
Tabelle die Objektadressen der referenzierten Objekte ermitteln. Diese Objektadresse kann dann anstelle der
Schlüsseleigenschaften zur Bestimmung der referenzierten Objekte verwendet werden. Auf diese Variante wird
im Rahmen der Optimierungen genauer eingegangen.
Vorteile:
°
°
°
Keine Initialisierung
Keine Suche pro Datensatz
Kein lokaler Suchbaum
63
Nachteile:
°
Die Objektadresse muss manuell (bei Konstanten) oder über die Datenbank (JOIN) ermittelt werden
Suche unter Verwendung der Referenz
Komponentenobjekte werden oft mit ihrer Referenz definiert, die gleichzeitig als Dokumentation dient. Definiert
man als Schlüsseleigenschaft eines Komponentenobjekts die Eigenschaft Referenz ([email protected]:
reference), so kann auch die komplette Referenz mit Softwarekomponente angegeben werden und es wird
diese ohne Suche auf der Datenbank im Client-Cache des Fabasoft Components Kernels aufgelöst, da dieser
Cache alle Komponentenobjekte enthält. Als Suchmethode muss auch hier „Prüfung durch Suche für jedes
Objekt“ verwendet werden.
Diese Suchmethode eignet sich hervorragend zur Definition von fixen Komponentenobjekten (z.B. ACLs, Stellen
oder Portalen), die in Eigenschaften anderer Objekte eingetragen werden sollen.
Welche Suchmethode soll verwen,erden?
Wenn man von der Verwendung spezieller Suchmethoden (Hashtabelle, Objektadresse) absieht, werden in
Abbildung 14 die wichtigsten Kriterien zur Auswahl der Suchmethode dargestellt.
Die erste Entscheidung hängt davon ab, ob bestehende Objekte geändert oder referenziert werden sollen. Kann
beides ausgeschlossen werden, so muss in der Fabasoft Components Domäne nicht gesucht werden. In diesem
Fall kann entweder „Keine Prüfung vorhandener Objekte“ ausgewählt werden oder, sofern Objekte innerhalb des
Imports mehrmals verwendet werden sollen, die „Suche im lokalen Cache“.
Falls bestehende Objekte verwendet werden sollen, muss zuerst geklärt werden, ob die Verwendung eines Suchbaumes zulässig ist, was vor allem vom zur Verfügung stehenden Speicher abhängt. Es sollten dabei nicht mehr
als etwa eine Million Objekte im Suchbaum gespeichert werden. Kann ein Suchbaum verwendet werden, hängt
die Suchmethode noch vom Verhältnis der referenzierten zu den existierenden Objekten ab. Wird nur ein kleiner
Teil der Objekte verwendet, so zahlt sich das „Sammeln der Schlüsseln für alle Objekte“ nicht aus und es sollte
die „Suche für jedes Objekt“ verwendet werden. Die endgültige Entscheidung hängt aber auch von vielen
4. Datenimportobjekt
4.4 Identifikation und Duplikatsprüfung
anderen Faktoren, wie zum Beispiel der Verwendung von Datenbankindizes oder der Komplexität der ACLPrüfung ab. Daher muss diese Entscheidung für jeden Anwendungsfall neu verifiziert werden.
Abbildung 14
Auswahl der Suchmethoden
Wenn von einer Objektklasse nur wenige 100 Instanzen referenziert werden, sollte der Defaultwert „Prüfung
durch Suche für jedes Objekt“ verwendet werden.
Mögliche Probleme bei Schlüsseleigenschaften
Get-Aktionen
Get-Aktionen bei Schlüsseleigenschaften können zur Folge haben, dass der Wert auf der Datenbank nicht mit
jenem Wert übereinstimmt, der beim Lesen der Eigenschaft des Objekts berechnet wird. Daher wird die Methode „Prüfung durch Suche für jedes Objekt“ möglicherweise nicht zum selben Ergebnis kommen, wie die „Prü-
65
fung durch Sammeln von Schlüsseln für alle Objekte“, da im einen Fall auf der Datenbank gesucht wird, im anderen Fall der von der Get-Aktion berechnete Wert verwendet wird. Solche Situationen sind aber nicht nur für den
Datenimport problematisch, sondern auch für die normale Suche in der Benutzerschnittstelle.
Set-Aktionen
Wenn der Wert einer Schlüsseleigenschaft in einer Set-Aktion geändert wird, wird diese Änderung im lokalen
Suchbaum nicht berücksichtigt und die Suche kann unvorhersehbare Resultate liefern. Beispielsweise kann
dadurch ein Objekt innerhalb eines Datenimports öfters referenziert werden und beim nächsten Datenimport
wird es auf einmal nicht mehr gefunden, da der Schlüsselwert jetzt auf Basis des Werts der Eigenschaft des
Objekts bestimmt wird, der aber durch die Set-Aktion nicht mehr dem ursprünglich gesetzten Wert entspricht.
Speicher
Auf 32-Bit-Betriebssystemen kann ein Prozess maximal drei Gigabyte Speicher direkt adressieren. Das ist bei der
Verwendung von lokalen Suchbäumen insofern zu berücksichtigen, als pro Eintrag mit ca. 40 Byte plus der
Länge des Werts der Schlüsseleigenschaft zu rechnen ist. Wenn der Import auf 64-Bit-Systemen durchgeführt
wird, sind die Speichergrenzen zwar nicht relevant, jedoch sind durch die größeren Pointer 12 Byte mehr pro
Objekt zu berechen.
Optimierung der Suche
Es ist vorteilhaft nur eine Schlüsseleigenschaft pro Objektklasse zu verwenden, da in diesem Fall die Suche effizienter ist und weniger Zugriffe auf Eigenschaften gemacht werden müssen. Bei den Suchmethoden, die pro
Objekt suchen, sollte diese Eigenschaft auf der Datenbank mit einem Index auf den Wert versehen sein.
Besonders gut geeignet sind die Eigenschaften Externer Schlüssel ([email protected]:
objexternalkey) und Betreff ([email protected]:objsubject) falls diese nicht anderwärtig verwendet werden.
4. Datenimportobjekt
4.4 Identifikation und Duplikatsprüfung
Die Eigenschaft Externer Schlüssel ist speziell für solche Zwecke definiert worden und hat nur den Nachteil,
dass die Werte auf der Datenbank in der generischen Tabelle atstrval stehen, wie die Werte vieler anderer Eigenschaften auch. Daher ist diese Eigenschaft nicht so effizient indizierbar. Das lässt sich aber bei Bedarf
durch die Implementierung geeigneter Tabellendefinitionen auf der Datenbank und entsprechender Indizierung
entschärfen.
Die Eigenschaft Betreff wird in vielen Formularen angezeigt, eignet sich daher nur dann, wenn die Schlüsselwerte „lesbare“ und für den Benutzer relevante Information beinhalten. Die Werte der Eigenschaft finden sich
in der Tabelle cooobject und die Suche ist nach der Definition eines Indexes auf diese Spalte sehr effizient.
Da die Suche in der Regel neben der Schlüsseleigenschaft auch die Objektklasse als Bedingung enthält, kann
sie durch die Verwendung eines kombinierten Indexes nach der Objektklasse und der Schlüsseleigenschaft weiter optimiert werden. Welcher Index im konkreten Fall optimal ist, kann – sieht man von der Definition von Tabellen ab – mit den Analysewerkzeugen der Datenbank ermittelt werden.
Suchbereiche
Suchbereiche dienen primär der Einschränkung der Suche auf bestimmte Fabasoft Components Domänen,
Fabasoft Components COO-Stores oder Fabasoft Components COO-Services. Einerseits kann damit die Suche
auf jene Services eingeschränkt werden, die auch tatsächlich Daten der betreffenden Objektklasse beinhalten,
andererseits kann man aber auch die Suche auf bestimmte Mandanten oder Ausschnitte der Objektmenge
beschränken. Wegen der gemeinsamen Verwaltung der Schlüssel einer Objektklasse kann auch der Suchbereich
nur pro Objektklasse und nicht pro Funktion eingestellt werden. Werden unterschiedliche Suchbereiche bei einer
Objektklasse definiert, ist das Resultat nicht definiert.
Eine wenig bekannte Möglichkeit bietet die Verwendung von Suchbereichen beim Erzeugen von Objekten: Wird
genau ein Fabasoft Components COO-Store im Suchbereich definiert, so werden neue Objekte dieser Objektklasse genau auf diesem Fabasoft Components COO-Store erstellt. Es wird also die Objektplatzierung überschrieben. Das kann einerseits dafür verwendet werden, dass bei Migrationen die Änderungen auf genau definierten
Fabasoft Components Services vorgenommen werden und andere Fabasoft Components Services nicht berührt
67
werden, wodurch eine Trennung der Datenbestände erreicht werden kann. Andererseits kann diese Trennung
auch für explizite Verteilung der Last auf mehrere Fabasoft Components Services verwendet werden, wenn zum
Beispiel ein Datenbestand auf mehrere Datenpakete aufgeteilt wird und von mehreren Clients aus möglichst
schnell in eine Fabasoft Components Domäne eingespielt werden soll.
Hintergrund: DesignPatterns 2001
Schon bei den Fabasoft DesignPatterns im Jahr 2001 wurde in einer Demo der Import von 10 Mio. Objekten in einer Stunde live vorgeführt. Dafür wurden die Quelldaten auf fünf Clients gleichmäßig aufgeteilt.
Bei der Optimierung stellte sich heraus, dass die Fabasoft Components COO-Services, vor allem aufgrund
von Datenbank-Locks, den geforderten Durchsatz nicht erreichen konnten. Was mit einem einzelnen Datenservice aber auch mit einer zufälligen Verteilung der Objekte über die Objektplatzierung nicht erreicht werden konnte, ließ sich durch die Implementierung einer Objektplatzierung über die Suchbereiche bewerkstelligen, indem in jedem der fünf verwendeten Datenimportobjekte ein anderer Suchbereich und damit ein
anderes Service zugeteilt wurde. So optimiert konnte der Import auf der im Vergleich zu heutigen Rechnern
langsamen Hardware in der geforderten Zeit durchgeführt werden.
Objektsperren
Objektsperren dienen der Synchronisation von Änderungen an einem Objekt und sorgen dafür, dass jedes Objekt
von maximal einer einzigen Transaktion modifiziert wird.
Dieser Mechanismus benötigt erheblich viel Zeit, da für jede Sperre ein RPC an das betreffende Fabasoft Components COO-Service abgesetzt wird und von diesem in einer eigenen Transaktion die Sperre auch in der Datenbank eingetragen wird. Beim Lösen der Sperre werden nach dem Commit alle Objektsperren eines Fabasoft
Components COO-Services in einer Transaktion wieder gelöscht. Sind die Objektsperren aktiviert, kann es
dadurch natürlich auch zu dem Fall kommen, dass ein Objekt bereits in einer anderen Transaktion gesperrt ist.
In diesem Fall werden vom Datenimport keine Änderungen auf diesem Objekt durchgeführt, Änderungen an
anderen Objekten werden jedoch ganz normal durchgeführt. Der Datensatz wird zur Fehlerbehandlung in das
4. Datenimportobjekt
4.4 Identifikation und Duplikatsprüfung
4.5 Parameter der Verarbeitung
Redo-Log geschrieben und damit können mit einem Roll-Forward die fehlenden Änderungen zu einem späteren
Zeitpunkt nachgetragen werden.
Gerade bei großen Datenübernahmen kann man organisatorisch (z.B. durch ein Wartungsfenster) dafür sorgen,
dass gleichzeitig mit dem Datenimport keine Änderungen auf den betroffenen Objekten durchgeführt werden.
Daher werden beim Datenimport die Objektsperren nicht verwendet, außer man schaltet diese explizit bei den
Klasseneigenschaften durch das Setzen der Eigenschaft Objekte sperren ([email protected]:
datimplockobjects) auf den Wert „Ja“ ein.
4.5
Parameter der Verarbeitung
Transaktionen und Threads
Während das Lesen der Quelldaten immer sequenziell von einem einzelnen Thread durchgeführt wird, werden
Änderungen in einem oder mehreren parallelen Worker Threads durchgeführt (siehe Abbildung 4). Dazu wird
vom Reader Thread eine bestimmte Anzahl von Datensätzen in einen Datenblock zusammengefasst, der jeweils
an einen einzelnen Worker Thread zu Verarbeitung übergeben wird. Dieser Worker führt daraufhin die Änderungen aller Datensätze eines Blockes in einer Transaktion durch und führt das Commit dieser Transaktion durch.
Das dient vor allem dazu, den Overhead, der für jede Transaktion notwendig ist, möglichst klein zu halten. Daneben kann dieser Mechanismus auch gezielt bei der Optimierung eingesetzt und auf die jeweilige Situation abgestimmt werden.
Parallele Threads
Ein wichtiger Faktor beim optimalen Tuning von Datenimporten ist die Verwendung von Parallelität bei der Verarbeitung von Datenimporten. Bei der Verwendung von parallelen Threads werden die Datenblöcke, die vom
Reader sequentiell erstellt werden, von einer fixen Anzahl von Worker Threads aus einer Queue gelesen. Jeder
Worker Thread nimmt sich also genau einen Datenblock von der Queue und verarbeitet diesen vollständig bevor
er den nächsten Datenblock aus der Queue entnimmt.
69
Die Verarbeitungs-Threads laufen parallel, sofern sie nicht durch den Zugriff auf gemeinsame Ressourcen synchronisiert werden. Zu den gemeinsamen Ressourcen zählen
°
°
°
°
°
Zu modifizierende Objekte
Nummeratoren
Hashtabellen
Skripts vor und nach dem Commit
Fabasoft Components Kernel
Der Fabasoft Components Kernel stellt für jede Verarbeitung eine zentrale Ressource dar und führt in vielen Fällen auch dazu, dass auch auf Multiprozessorsystemen maximal jene CPU-Last vom importierenden Prozess verbraucht wird, die einer einzelnen CPU entspricht. Während der Ausführung von RPCs zu Fabasoft Components
COO- und Fabasoft Components MMC-Services kann jedoch der Fabasoft Components Kernel von einem anderen Thread verwendet werden. Daher kann besonders in den Fällen, bei denen die Suche nach Objekten oder das
Schreiben der Daten auf der Datenbank erhebliche Zeit in Anspruch nimmt, diese Zeit am Ladeclient von anderen parallelen Worker Threads genutzt werden.
Die Skripts werden später in einem eigenen Abschnitt behandelt. Aufgrund von Einschränkungen der Scripting
Engine wird die Verarbeitung der Skripts serialisiert.
Die wichtigste Einschränkung ist aber jene der zu ändernden Objekte des Datenmodells. Die Einschränkung lautet, dass ein Objekt nicht gleichzeitig in mehreren Transaktionen geändert werden darf. Normalerweise dient der
Mechanismus der Objektsperre dazu, solche Zugriffe zu verhindern. Doch wenn die Objektsperren wegen des
großen Ressourcenbedarfs nicht verwendet werden, muss garantiert werden, dass innerhalb eines Datenimports mehrere Worker Threads nicht gleichzeitig dasselbe Objekt ändern. Daher gibt es einen internen Synchronisationsmechanismus, der das verhindert.
Zuerst wird dabei festgestellt, ob ein Objekt in der Transaktion potenziell erzeugt oder verändert wird. Dazu werden alle Zuordnungen herangezogen, die Veränderungen hervorrufen können. Zudem werden bei Rückwärtsverkettungen beide Richtungen der Zuweisung berücksichtigt. Nicht berücksichtigt können jene Änderungen wer-
4. Datenimportobjekt
4.5 Parameter der Verarbeitung
den, die von Methoden durchgeführt werden, da diese Änderungen nicht explizit modelliert sind und daher dem
Datenimport nicht bekannt sind. Von jenen Objektklassen, deren Objekte potenziell verändert werden, wird im
Rahmen vor dem Suchen bzw. Erzeugen der Objekte eine Liste der verwendeten Schlüssel geführt und jeder
Schlüssel kann dabei exklusiv nur von einem Thread verwendet werden. Trifft ein Thread auf ein bereits gesperrtes Objekt wird die Ausführung dieses Threads solange angehalten, bis das betroffene Objekt wieder freigegeben wird, also bis der blockierende Thread die Verarbeitung des aktuellen Datenblocks beendet hat.
Eine andere häufig anzutreffende Einschränkung ist die Vergabe von Nummeratorwerten, also die aufsteigende
Nummerierung von Objekten, sei es über einfache Nummeratoren oder Schlüssel-Nummeratoren. Während der
Schlüsselvergabe werden die Nummeratorobjekte gesperrt und diese Sperre wird erst nach dem Commit der
aktuellen Transaktion wieder aufgehoben. Daher steht der Nummerator nur einem Thread zur Verfügung. Der
Auflösung dieses Problems ist ein eigener Abschnitt dieses Buches gewidmet.
Hashtabellen müssen beim Erzeugen von Objekten wegen der Kollisionsbehandlung exklusiv gesperrt werden,
bis die Objekte auf die Datenbank persistiert sind und führen daher auch zu einer Serialisierung der Verarbeitung. Diese kann nicht umgangen werden.
Gruppenwechsel
Oft werden einzelne Objekte durch mehrere Datensätze verändert (z.B. beim Setzen von Listen). In der Verarbeitung bringt es Vorteile, wenn Objekte in möglichst wenigen Transaktionen geändert werden. Einerseits müssen
dann weniger Änderungen geschrieben werden, da weniger unvollständige Stände des Objekts committet werden, andererseits kann dadurch die Parallelität erhöht werden, da ein Objekt zu jedem Zeitpunkt nur an einer einzigen Transaktion beteiligt sein darf.
Daher wurde die Option „Gruppenwechsel“ implementiert, die bei den Zuordnungen von Datenbankspalten
angegeben werden kann. Damit wird die Anzahl der Datensätze, die vom Reader Thread in einen Datenblock
gegeben wird, dynamisch verändert. Das wird erreicht, indem die Änderung einer oder mehrerer Datenbankspalten (im Normalfall die Schlüsselspalten eines zu ändernden Objektes) bewirken, dass ein Datenblock vom
Reader Thread nicht mehr weiter befüllt wird und zur Weiterverarbeitung an einen Worker Thread gegeben wird.
71
Für die Blockgröße werden eine minimale und eine maximale Größe angegeben. Jeder Datenblock wird jedenfalls bis zur minimalen Größe befüllt und dann werden weitere Datensätze hinzugefügt bis entweder die maximale Blockgröße erreicht ist oder sich der Wert mindestens einer der Spalten, bei denen die Option gesetzt ist,
verändert. Voraussetzung für den effizienten Einsatz dieser Option ist jedoch, dass die Datensätze sortiert von
der Datenquelle geliefert werden, was bei manchen Datenquellen (z.B. LDAP) implizit der Fall sein kann, bei
anderen Datenquellen (z.B. Datenbanken, die über OLE DB angebunden sind) über SQL-Anweisungen mit einem
ORDER BY explizit herbeigeführt werden muss. Ist das für die Spalten mit Gruppenwechsel gewährleistet, so
kann man garantieren, dass alle Datenbereiche mit gleichen Gruppenwechsel-Spalten, die nicht mehr Datensätze umfassen als Maximale Blockgröße minus Minimale Blockgröße in einem Block und somit in einer
Transaktion verarbeitet werden.
Werden Änderungen also vor allem an einer Objektklasse durchgeführt, dann empfiehlt es sich den Gruppenwechsel dazu zu verwenden, möglichst alle Änderungen eines Objekts in einer einzelnen Transaktion durchzuführen.
Speziell bei der Synchronisation von Listen ist dieser Mechanismus unerlässlich, da der Synchronisationsmechanismus voraussetzt, dass die Liste in einer einzigen Transaktion wieder aufgebaut wird.
Übergehen von Methoden
Das Übergehen von Methoden ist eine mächtige Tuningmaßnahme, die nur mit großer Vorsicht verwendet werden darf. Worum geht es dabei?
In Fabasoft Components werden sowohl beim Erzeugen von Objekten als auch beim Commit der Transaktion
Methoden auf die einzelnen Eigenschaften und auf alle erzeugten bzw. geänderten Objekte ausgeführt. In diesen Methoden ist ein Teil der Anwendungslogik implementiert und daher benötigen diese Methoden oft sehr viel
Zeit. Bei Migrationen ist diese Anwendungslogik jedoch oft nicht notwendig, da etwa Konsistenzprüfungen
bereits vor dem Datenimport durchgeführt oder andere Berechnungen bereits im Rahmen des Imports gemacht
werden können (z.B. die Zusammensetzung des Objektnamens aus einzelnen Eigenschaften). In diesen Fällen
kann also die Anwendungslogik durch Logik des Datenimports ersetzt werden. In manchen Fällen müssen die
4. Datenimportobjekt
4.5 Parameter der Verarbeitung
Methoden während der Migration überhaupt unterdrückt werden, da sie unerwünscht sind, wie zum Beispiel der
Eigenschaftskonstruktor der Eigenschaft Prozesse ([email protected]:workflow), der beim Erzeugen des
Objekts einen definierten Workflow instanziert.
Folgende Aktionen können übergangen werden:
°
°
°
°
°
Die Konstruktoren von Eigenschaften
Die Aktion vor dem Schreiben der Eigenschaften (Set-Aktionen)
Der Objektkonstruktor ([email protected]:ObjectConstructor)
Die Aktion vor dem Schreiben der Objekte ([email protected]:ObjectPrepareCommit)
Die Aktion nach dem Schreiben der Objekte ([email protected]:ObjectCommitted)
Damit kann man meistens alle relevanten Methoden, die im Rahmen der Erstellung der Objekte aufgerufen werden, deaktivieren.
Die Deaktivierung wird durch die Registrierung von dynamischen Pre-Wrappern implementiert, die vor der Ausführung der eigentlichen Methoden den Fehlerstatus [email protected]:COOSTERR_BREAK setzen,
wodurch der Fabasoft Components Kernel die Verarbeitung der Methode abbricht. In seltenen Fällen ist bei
Aktionen eine der Eigenschaften Keine Wrapper-Methoden ausführen oder Muss ausgeführt werden auf
„Ja“ gesetzt, dann kann auch die Ausführung vom Datenimport nicht verhindert werden.
Methoden ohne Prüfung übergehen?
Im dynamischen Pre-Wrapper wird normalerweise geprüft, ob es sich bei der aufgerufenen Methode wirklich
um die Methode der richtigen Eigenschaft bzw. Objektklasse handelt. Sonst würden zum Beispiel bei
[email protected]:ObjectPrepareCommit die Aufrufe bei allen Objektklassen deaktiviert. Wenn
aber selbst diese Überprüfung zu aufwendig ist oder der erwähnte Seiteneffekt gewünscht ist, kann durch das
Setzen von Methoden ohne Prüfung übergehen? auf „Ja“ diese Prüfung deaktiviert werden. Diese Option
sollte aber nur von Experten und mit entsprechender Vorsicht eingesetzt werden.
73
4.6
Importoptionen und Protokoll
Protokoll: Modus, Objekt, max. Einträge
Während des Datenimports besteht die Möglichkeit ein Protokoll der Datensätze, der beteiligten Objekte und
der Fehler zu erstellen. Es kann dabei zwischen
°
°
°
„Kein Protokoll“
„Protokolliere Fehler“ und
„Vollständiges Protokoll“
gewählt werden, je nachdem, ob überhaupt eine Protokolldatei angelegt werden soll, ob darin nur die Fehler enthalten sein sollen oder ob alle Datensätze im Protokoll enthalten sein sollen.
Wenn das „Vollständige Protokoll“ ausgewählt ist, dann werden die Daten aller Quelldatensätze und zusätzlich
die Objektadressen aller erzeugten oder geänderten Objekte ins Protokoll geschrieben. Genauso wie bei „Protokolliere Fehler“ werden auch die Fehlermeldungen im Protokoll vermerkt.
Dieses Protokoll wird während des Datenimports auf eine lokale Datei geschrieben, die nach Verarbeitung aller
Datensätze an die Liste der Protokolle im Protokoll-Objekt gemeinsam mit den Statistikinformationen angehängt
wird.
Wird ein vollständiges Protokoll oder ein Fehlerprotokoll geschrieben, so ist in den Skripts (Filterskript für Rohdaten, Skript für Objekte und Skript für Objekte nach dem Commit) ein COM-Objekt definiert, das erlaubt,
eigene Informationen ins Protokoll zu schreiben.
Änderungen sofort anzeigen
Diese Option stammt noch aus den Zeiten des Fabasoft Win32-Clients, bei dem nach dem Commit eines Objekts
auch alle angezeigten Fenster von Änderungen verständigt wurden und diese entsprechend aktualisiert wurden.
Um diesen Vorgang zu vermeiden, wird bei Datenimporten standardmäßig die Transaktionsvariable
4. Datenimportobjekt
4.6 Importoptionen und Protokoll
4.7 Skripts
TV_NOUIREFRESH der Softwarekomponente [email protected] gesetzt. Bei Datenimporten, bei denen
der Datenimport vom Web- oder AT-Service durchgeführt wird, hat diese Option keinerlei Auswirkungen.
Objekte nicht aktualisieren
Jedes Objekt, das von einer Transaktion betroffen ist, wird normalerweise – sofern es sich nicht um Komponentenobjekte handelt – auf seine Aktualität hin geprüft. Dafür wird beim entsprechenden Fabasoft Components
COO-Service das Änderungsdatum des Objekts ausgelesen. Kann man sicherstellen, dass während des Datenimports keine Objekte auf anderen Fabasoft Components Kernel-Instanzen geändert werden, die später noch
einmal vom Datenimport betroffen sind, dann kann man auf diese Aktualisierung verzichten, indem man diese
Eigenschaft auf den Wert „Ja“ setzt und erreicht damit eine erhebliche Performancesteigerung.
In Version 7 ist ein neuer Mechanismus zur Verteilung von Änderungsmeldungen implementiert, bei dem die
Fabasoft Components COO-Services, wenn ein Objekt in einer Transaktion modifiziert wurde, aktiv über Multicast-Messages alle Fabasoft Components Kernel-Instanzen von Änderungen der Objekte benachrichtigen. Wird
dieser Mechanismus verwendet, so kann der Fabasoft Components Kernel entscheiden, ob ein Objekt im Cache
noch aktuell ist, ohne jedes Mal Aktualisierungsanfragen an das Fabasoft Components COO-Service stellen zu
müssen. Daher zeigt diese Option hier kaum Auswirkungen.
4.7
Skripts
In die Verarbeitung der Datenimporte kann an drei Stellen durch Verwendung von Skripts eingegriffen werden.
Diese Skripts können unter Microsoft Windows als VBScript oder JavaScript implementiert werden, unter Linux
jedoch ausschließlich als JavaScript. Der globale Kontext der Skripts wird beim Start des Datenimports einmalig aufgerufen. Dort können globale Variablen definiert werden oder Initialisierungen vorgenommen werden.
Danach wird für jeden Datensatz eine Funktion Main (bzw. beim Filterskript für Rohdaten alternativ
MainEx) aufgerufen, der die entsprechenden Parameter übergeben werden.
75
Die MainEx-Variante dieser Funktion wurde deshalb implementiert, weil mit dem zunehmenden Einsatz von
Linux die Einschränkung auf VBScript zur Implementierung der Skripts beseitigt wurde. Diese Einschränkung war
eine Folge der Verwendung von SafeArrays zur Parameterübergabe im Filter für Rohdaten.
Filterskript für Rohdaten
Das Skript für Rohdaten dient der Berechnung von Werten auf Basis der Eingangsdaten aus der Datenquelle.
Hier können auch Kriterien definiert werden, um gezielt Datensätze herauszufiltern. Dieses Skript wird vom
Reader Thread ausgeführt, wobei beim Start des Imports einmalig der globale Skript-Kontext ausgeführt wird
und dann pro Datensatz, der von der Datenquelle geliefert wird, die Funktion Main bzw. alternativ dazu die
Funktion MainEx aufgerufen wird. Dieser Funktion werden die Werte der Datenquelle übergeben und diese
können in der Funktion geändert werden. Zusätzlich zu den „normalen“ Datenbankspalten, die von der Datenquelle stammen, gibt es noch die Möglichkeit zur Verwendung „berechneter“ Spalten, also Spalten, die nicht
von der Datenquelle befüllt werden, sondern von diesem Skript gesetzt werden. Diese berechneten Spalten können bei den Zuordnungen genauso wie die eigentlichen Datenbankspalten verwendet werden. Zur Unterscheidung zwischen Datenbankspalten und berechneten Spalten dient ein „@“ am Beginn der berechneten Spalten.
Die Funktion Main(columns, data, changed, skip) ist die ursprüngliche Form der Funktion,
die in diesem Skript ausgeführt wird. Bei dieser Funktion wird als erster Parameter (columns) ein 0-basiertes
Array von Zeichenketten übergeben, in dem die Spaltennamen aller bei den Zuordnungen verwendeten Spalten
enthalten sind. Einträge, die in der Tabelle der Zuordnungen mehrfach verwendet werden, sind hier nur einmal
enthalten. Neben den Datenbankspalten sind hier auch die berechneten Spalten enthalten, also alle Einträge,
die in der Tabelle Zuordnungen in der Eigenschaft Spalte enthalten sind, selbst wenn die Zeile den Schlüssel- und Änderungsmodus „Ignorieren“ hat. Diese Spaltennamen hängen mit dem zweiten Parameter – den
Daten – zusammen, in dem der Wert der jeweiligen Spalte unter demselben Index im Parameter data zu finden ist, wie der Spaltenname im Parameter columns. Der Parameter data ist also auch ein Array – wieder
von Zeichenketten – in dem die Daten enthalten sind. NULL-Werte werden durch leere Zeichenketten abgebildet, sodass kein Unterschied zwischen einem leeren String und einem nicht vorhandenen Wert gemacht wird.
Berechnete Spalten sind ebenfalls mit Leerstrings initialisiert. Ändert man etwas an den Daten, befüllt man also
4. Datenimportobjekt
4.7 Skripts
zum Beispiel eine berechnete Spalte mit einem Wert, so muss man darauf achten, dass wieder nur Zeichenketten an den richtigen Index im Parameter data geschrieben werden. Außerdem werden Änderungen nur dann
übernommen, wenn der Parameter changed auf „True“ gesetzt wird. Wird changed auf dem Initialisierungswert „False“ belassen, werden die Änderungen ignoriert. Außerdem können in diesem Skript Datensätze
gänzlich von der weiteren Verarbeitung ausgeschlossen werden, indem der Parameter skip auf den Wert
„True“ gesetzt wird.
In der Funktion MainEx(params) werden diese Parameter nicht in Form von Arrays bzw. booleschen Variablen, sondern als DICTIONARY übergeben, das alle diese Parameter beinhaltet. Dies ist notwendig, da
JavaScript das Schreiben von SafeArrays nicht unterstützt und es damit unter Linux, wo ja VBScript nicht zur
Verfügung steht, nicht möglich war, ein Filterskript zu schreiben, das Rohdaten berechnet oder verändert. Nebenbei lässt sich damit auch wesentlich kompakterer Skript-Code schreiben, da das mühsame Suchen nach dem
richtigen Index einer Spalte entfällt. Beispiele dafür finden sich im Kapitel „Zusätzliche Beispiele“ auf Seite 159.
Filter für Objekte
Es gibt zwei Filter für Objekte, die sich einzig durch den Zeitpunkt des Aufrufes innerhalb der in Abbildung 15
beschriebenen Verarbeitungsfolge eines Datenpaketes im Worker Thread unterscheiden.
Wie beim Filterskript für Rohdaten wird der globale Kontext des Skripts auch bei diesen Skripts bei der Initialisierung des Datenimports einmalig ausgeführt. Später wird dann pro Datensatz einmal die Funktion Main aufgerufen. Im Unterschied zum Filterskript für Rohdaten werden jetzt aber nicht die Quelldaten an das Skript
übergeben, sondern die an dem Datensatz beteiligten Objekte. Als Parameter werden drei Arrays übergeben, die
– wiederum über den Array-Index zusammenhängend – die Referenz der Objektklasse, die Objekt-ID und das
konkrete Objekt beinhalten. Man verwendet also die Referenz der Objektklasse und die Objekt-ID um den richtigen Index in der Objektliste zu finden und kann dann direkt auf den Wert zugreifen. Beachten muss man jedoch,
dass der Wert des Objekts nicht in jedem Fall gesetzt sein muss. Wird ein Objekt nicht gefunden und auch nicht
erzeugt oder kann es (falls das konfiguriert ist) nicht gesperrt werden, so ist der Eintrag in der Objektliste leer.
Daher sollte man gerade bei der Verwendung von VBScript, wegen dessen anachronistischen Verwendung von
77
Zuweisungen zu Variablen, zuerst mit einer Abfrage (z.B. mit IsObject(value(n))) feststellen, ob in der
betreffenden Zelle ein Wert enthalten ist, bevor man diesen einer Variable zuweist oder anderweitig verwendet.
In JavaScript verwendet man dafür einen Vergleich auf != null.
Abbildung 15
Verarbeitung der Datensätze im Worker Thread
Hat man die betreffenden Objekte identifiziert und ihre Gültigkeit festgestellt, so kann man darauf Aktionen ausführen oder Eigenschaften lesen und setzten. Man kann dabei auch beliebige Objekte verwenden, die sonst nicht
im Datenimport verwendet werden, wobei immer darauf geachtet werden muss, dass man dazu nicht die globale Transaktion cootx verwendet, sondern die als vierten Parameter übergebene Transaktion threadtx,
denn das ist jene Transaktion, in der die Objekte gesucht, erzeugt und verändert wurden. Neu erzeugte Objekte
sind nur in dieser Transaktion bekannt und die Verwendung einer anderen Transaktion könnte daher zu Problemen und Inkonsistenzen führen.
4 Datenimportobjekt
4.7 Skripts
Als Anwendungsfälle für das Filterskript für Objekte seien die Versionierung und die Protokollierung von
Änderungen genannt. Dazu finden Sie auch Beispiel-Skripts bei den Konfigurationsbeispielen im Kapitel
„Zusätzliche Beispiele“ auf Seite 159.
Filter für Objekte nach dem Commit
Gleich wie das vorhergehende Skript wird auch beim Filterskript für Objekte nach dem Commit pro Datensatz die Main-Funktion mit denselben Parametern aufgerufen. Jedoch nur dann, wenn das Commit der Transaktion erfolgreich durchgeführt werden konnte.
Als Anwendungsfall ist im Kapitel „Zusätzliche Beispiele“ auf Seite 159 ein Skript für die Archivierung der
Inhalte der Objekte hinterlegt. Man kann aber genauso gut auch hier Protokollierungen durchführen oder – wie
bereits einmal im Rahmen eines periodischen Abgleichs durchgeführt – den Datensatz, der in dieser Datenzeile
verarbeitet wurde, in einer Datenbank als verarbeitet markieren.
Grundsätzlich sollte man jedoch alle diese Skripts mit großer Vorsicht einsetzen, da Skripts selbst und oft auch
die darin aufgerufenen Funktionen (z.B. die Versionierung oder Archivierung) langsam sind und den Datendurchsatz des Datenimports erheblich mindern. Durch eine unsachgemäße Verwendung von Skripts sind schon ganze
Migrationen gefährdet worden, indem sie derart ineffizient eingesetzt wurden, dass die Migration in der zur Verfügung stehenden Zeit nicht mehr durchführbar war. In einem Fall konnte durch ein Redesign der Filterskripts die
Verarbeitung um den Faktor 100 beschleunigt werden.
79
5
Was man unbedingt
5 beachten sollte …
5.1
Nummeratoren
Nummeratoren sind Zahleneigenschaften, die automatisch mit sequenziell aufsteigenden Werten befüllt werden. Eine Möglichkeit ist, diese Zahlen global zu vergeben, wie zum Beispiel bei der Eigenschaft Einfache
Namenszahl ([email protected]:nameid) der Objektklasse Einbringer ([email protected]:
Applicant), durch die jeder Einbringer eine eindeutige ID erhält. Die andere Variante sind Schlüssel-Nummeratoren, bei denen die Zahlen für jeden Wert der für diesen Nummerator definierten Schlüsseleigenschaften getrennt vergeben werden. Prominentes Beispiel dafür ist die Eigenschaft ESt-Nr
([email protected]:incnr) der Eingangsstücke ([email protected]:Incoming), die pro Jahr
vergeben wird. Hier wird in Abhängigkeit vom Wert der Eigenschaft Jahr ([email protected]:year) ein
anderer Zähler zur Vergabe der Nummer verwendet.
Während beim Nummerator der Wert beim Erzeugen der Eigenschaft vergeben werden kann, kann der Wert
beim Schlüssel-Nummerator erst ermittelt werden, wenn die Schlüsseleigenschaft festgelegt ist, also erst vor
dem Commit des Objekts, wenn die Schlüsseleigenschaft bereits gesetzt ist.
Nummerator-Eigenschaften
Die Berechnung einer einfachen Nummerator-Eigenschaft wird im Konstruktor der Eigenschaft durchgeführt.
Dort wird zuerst das Nummerator-Objekt gesperrt, danach wird der Wert ausgelesen, um 1 erhöht und
wieder gesetzt. Im Normalbetrieb wird diese Änderung des Nummerator-Objekts sofort in einer eigenen Transaktion auf die Datenbank geschrieben und das Nummerator-Objekt damit wieder entsperrt, damit es auch andere Benutzer verwenden können, selbst wenn das nummerierte Objekt (z.B. der Einbringer) noch in Bearbeitung
und noch nicht comittet ist. Im Fall des Datenimports werden die Zugriffe auf das Nummerator-Objekt jedoch in
der Transaktion durchgeführt, in der die Objekte erzeugt und geändert werden. Damit erspart man sich das
oftmalige Sperren des Nummerator-Objekts, da dieses dann für die ganze Transaktion gesperrt bleibt und für alle
neu erzeugten Objekte ohne neuerliche Sperre verwendet werden kann. Dieser Performancegewinn bringt allerdings auch Nachteile mit sich. Offensichtlich ist, dass immer nur eine Transaktion diesen Nummerator verwenden kann. Alle anderen Transaktionen müssen warten, bis diese Transaktion abgeschlossen ist und der Numme-
81
rator damit wieder freigegeben wird. Dabei können durchaus auch Timeouts auftreten, wodurch selbst beim
Datenimport Probleme entstehen können. Daher sollte auch beim Import von Objekten mit Nummeratoren immer
nur ein Thread verwendet werden, außer man deaktiviert den Nummerator.
Dazu muss der Wert des Nummerators aus einer Spalte der Datenquelle oder einer berechneten Spalte befüllt
werden, indem man einen Eintrag in der Tabelle der Zuordnungen definiert, durch den der Nummerator-Eigenschaft ein Wert zugewiesen wird. Bei dieser Zuordnung setzt man zusätzlich die Optionen „Methoden zum
Erzeugen des Wertes übergehen“ und „Methoden zum Speichern des Wertes übergehen“. Dadurch wird jene
Aktion nicht ausgeführt, die den Wert der Nummerator-Eigenschaft über das Nummerator-Objekt berechnet. Die
Eigenschaft erhält daher den Wert, ohne dass das Nummerator-Objekt involviert ist und gesperrt werden muss.
Dadurch wird die Einschränkung betreffend der Parallelisierung aufgehoben.
Um den Wertebereich, die Gültigkeit und Eindeutigkeit des Werts der Nummerator-Eigenschaft muss man sich
selbst kümmern. Nach dem Abschluss des Imports darf man nicht vergessen, das Nummerator-Objekt, das ja im
Rahmen des Datenimports nicht auf den korrekten Wert gesetzt wurde und daher bei dem alten Wert weiterzählen würde, auf den höchsten verwendeten Wert zu setzen, da es sonst zu doppelten Schlüsselwerten kommen könnte. Dazu ruft man die Aktion Schlüsselwert korrigieren ([email protected]:
UpdateValue) auf jenes Objekt auf, das im Rahmen des Datenimports den höchsten vergebenen Wert
erhalten hat. Üblicherweise wird das in einem eigenen Datenimport gemacht. Dabei werden die betroffenen
Datensätze auf der Quelldatenbank in einer View über die Quelldaten ermittelt und im Filterskript für
Objekte diese Aktion aufgerufen.
Diese Vorgehensweise ist nur zulässig, wenn sichergestellt ist, dass während des Datenimports nicht manuell
oder durch andere Maßnahmen Objekte angelegt werden, die denselben Nummerator verwenden. Diese würden potenziell Nummern aus einem Bereich erhalten, die für Objekte des Datenimports bereits vergeben sind.
Um das zu verhindern, müssen in solchen Fällen schon vor dem Datenimport die Nummerator-Werte um jene
Anzahl erhöht werden, die im Rahmen des Imports vergeben wird. Damit kann jederzeit ein neues Objekt
manuell angelegt werden und es erhält jedenfalls eine andere Nummer als die vom Datenimport angelegten
Objekte.
5. Was man unbedingt beachten sollte
5.1 Nummeratoren
Schlüssel-Nummerator
Schlüssel-Nummeratoren werden, wie schon in der Einleitung erwähnt, nicht im Konstruktor der Eigenschaft
berechnet, sondern erst später, wenn bereits alle Eigenschaften gesetzt sind, durch die Aktion Erzeugen der
Nummerator-Werte ([email protected]:GenerateIDs) gesetzt. Wird ein Objekt im Rahmen eines
Use-Cases vom Benutzer angelegt, so wird im Objektkonstruktor, der bei den betroffenen Objekten als TriStep
durch die Methodendefinition [email protected]:TriStep implementiert ist, zuerst eine Initialisierung
vorgenommen ([email protected]:PreGUI), danach der Dialog angezeigt ([email protected]:
DispGUI) und danach noch ein Nachbearbeitungsschritt aufgerufen ([email protected]:PostGUI).
Die Berechnung der Werte des Schlüssel-Nummerators wird als Pre-Wrapper der PostGUI-Aktion, also direkt
nach dem Bearbeiten der Eigenschaften, durchgeführt.
Diese Vorgehensweise kann in dieser Form bei einem Datenimport nicht funktionieren, da die Eigenschaften des
Objekts vom Datenimport erst nach der Verarbeitung des Objektkonstruktors gesetzt werden, zu einem Zeitpunkt
also zu dem die PostGUI-Aktion bereits durchgeführt wurde. Daher gibt es grundsätzlich zwei Vorgehensweisen
beim Datenimport:
1. Wird der Nummerator für die Vergabe der Werte verwendet, so muss im Skript für Objekte vor dem Commit
die Aktion Erzeugen der Nummerator-Werte ([email protected]:GenerateIDs) explizit aufgerufen werden. Diese sperrt die betroffenen Nummerator-Objekte, was die bei den normalen Nummeratoren
besprochenen Probleme hervorruft. Diese Variante ist relativ langsam, dafür aber einfach umzusetzen.
Außerdem kann sie selbst beim Import von Daten während des Produktionsbetriebs ohne die Gefahr von
Inkonsistenzen eingesetzt werden.
2. Werden die Nummeratorwerte über den Datenimport gesetzt, so kann der Aufruf der Aktion entfallen, aber
es müssen im Nachhinein für jeden Schlüsselwert die Nummerator-Wert-Objekte durch den expliziten Aufruf der Aktion Schlüsselwert korrigieren ([email protected]:UpdateValue) auf das
Objekt mit den höchsten vergebenen Werten gesetzt werden. Die Berechnung der IDs in der Datenquelle ist
zwar nicht kompliziert, erfordert aber eine gewisse Erfahrung im Umgang mit der Programmierung von
Abläufen in SQL. Mit dieser Variante erreicht man eine bedeutend bessere Performance und kann damit
83
auch die Datenimporte parallelisieren. Allerdings darf man auch die Nacharbeiten nicht vergessen, damit
man nicht im Nachhinein mit inkonsistenten Daten konfrontiert ist, wenn die Benutzer nach dem Import
manuell neue Objekte erzeugen und diese einen bereits im Rahmen des Datenimports vergebenen Wert
bekommen.
Alles in allem sollte man die Warnung „Die Eigenschaft x der Objektklasse y ist ein Nummerator, nur 1 Thread
sollte verwendet werden“, die beim Datenimport ausgegeben wird, wenn Objekte einer Objektklasse mit Nummerator-Eigenschaften erzeugt werden, durchaus ernst nehmen und sich eingehend mit dem Thema befassen.
Wenn man das nicht tut, kann das einerseits den Datenimport sehr bremsen, andererseits kann es sogar zur Vergabe von doppelten Werten bei Nummerator-Eigenschaften kommen.
5.2
Protokoll
Das Protokoll des Datenimports wurde mit Version 4 auf XML umgestellt. Dadurch sind die Protokolle strukturiert und automatisiert auswertbar geworden. Als zusätzlichen Vorteil kann man seitdem auch vom Filterskript
für Rohdaten und aus beiden Filterskripts für Objekte Daten in das Protokoll schreiben. Dazu gibt es im globalen Scope des Skripts das Objekt coolog, das gesetzt ist, wenn als Protokollmodus „Protokolliere Fehler“
oder „Vollständiges Protokoll“ eingestellt ist. Wird kein Protokoll geschrieben, ist dieses Objekt im Skript auch
nicht gesetzt.
Von den Methoden, die auf dieses Objekt anwendbar sind, sind die folgenden zum Schreiben von Informationen
in das Protokoll verwendbar:
InsertComment
Parameter:
°
data: Eingangsparameter (BSTR)
Mit InsertComment wird ein XML-Kommentar in das Protokoll geschrieben, der den in data angegebenen Text enthält.
5. Was man unbedingt beachten sollte
5.1 Nummeratoren
5.2 Protokoll
LogString
Parameter:
°
°
°
data: Eingangsparameter (BSTR)
address: Optionaler Eingangsparameter (BSTR)
nodename: Optionaler Eingangsparameter (BSTR)
Mit LogString wird der angegeben Text als Wert in ein XML-Element mit dem Namen Entry geschrieben Der Wert wird dabei laut XML-Escaping behandelt, also „&“ durch „&amp;“ ersetzt, „<“ durch „&lt;“ usw.,
damit der Wert beim Lesen des XML wieder genau dem übergebenen Wert entspricht. Ist ein Wert address
angegeben, wird dieser als Wert des Attributs address in das Protokoll geschrieben. Mit dem Parameter
nodename kann der Name des XML-Elements geändert werden.
LogXML
°
°
°
xmldata: Eingangsparameter (BSTR)
address: Optionaler Eingangsparameter (BSTR)
nodename: Optionaler Eingangsparameter (BSTR)
Im Unterschied zu LogString wird bei LogXML der Wert ohne XML-Escaping in das Protokoll geschrieben,
sodass ganze XML-Fragmente eingefügt werden können.
Mit den folgenden vier Funktionen können auch komplexere XML-Strukturen erzeugt werden:
EnterElement
°
name: Eingangsparameter (BSTR)
Hiermit wird ein XML-Element mit dem übergebenen Namen begonnen.
85
LeaveElement
°
name: Eingangsparameter (BSTR)
LeaveElement schließt ein mit EnterElement begonnenens XML-Element. Um Problemen, die durch
den parallelen Zugriff auf das Protokoll entstehen könnten vorzubeugen, wird das Protokoll bei einem
EnterElement solange exklusiv für den bearbeitenden Thread gesperrt, bis alle begonnenen Elemente
wieder mit LeaveElement beendet wurden.
AddAttribute
°
°
name: Eingangsparameter (BSTR)
value: Eingangsparameter (BSTR)
Nach einem EnterElement können so lange mit AddAttribute Attribute zu dem XML-Element hinzugefügt werden, bis eine beliebige andere Funktion auf das Objekt ausgeführt wird.
AddValue
°
value: Eingangsparameter (BSTR)
Mit dieser Funktion wird der Wert value zum Text des XML-Elements hinzugefügt und dabei entsprechend
escaped.
5.3
Roll-Forward
Schreiben des Roll-Forward-Logs
Das Roll-Forward-Log ist jene Protokolldatei, in die bei jedem Datenimport die Rohdaten jener Datensätze
geschrieben werden, bei denen Verarbeitungsfehler aufgetreten sind. Entweder sind das einzelne Datensätze,
wenn etwa bei der Konvertierung von Werten auf den Typ der Eigenschaft ein Fehler aufgetreten ist oder ein
5. Was man unbedingt beachten sollte
5.2 Protokoll
5.3 Roll-Forward
Objekt nicht gesperrt werden konnte, oder alle Datensätze einer Transaktion, wenn in Rahmen des Commits ein
Fehler aufgetreten ist. Daher finden sich auch oft viel mehr Datensätze im Roll-Forward-Log, als Fehler aufgetreten sind.
Da diese Daten erst am Ende jeder Transaktion geschrieben werden, ist im Roll-Forward-Log der Stand der Rohdaten nach Ausführung des Filterskripts für Rohdaten enthalten, also inklusive der Änderungen und der
berechneten Spalten des Filterskripts für Rohdaten. Während der Ausführung des Ladevorgangs werden die
Daten in der Datei gesammelt und am Ende des Imports im Log-Objekt in der Inhaltseigenschaft Roll-ForwardLog abgelegt.
Verarbeiten des Roll-Forward-Logs
Der Inhalt des Roll-Forward-Logs wird beim Roll-Forward als Datenquelle verwendet. Das ist aber auch der
einzige Unterschied zu einem „normalen“ Datenimport. Es wird genauso das Filterskript für Rohdaten ausgeführt, das bei Bedarf diesen Spezialfall berücksichtigen muss, da die geänderten Spalten des ersten Imports
möglicherweise nicht noch einmal geändert werden dürfen.
Und – wie bei allen anderen Datenquellen auch – wird bei diesem Import wieder ein neues Roll-Forward-Log
mit allen bei der neuerlichen Verarbeitung aufgetretenen Fehlern geschrieben. Datensätze mit systematischen
Fehlern werden daher immer wieder im Roll-Forward-Log landen. Auch werden alle Datensätze von Transaktionen, bei denen einer der Datensätze den Abbruch der Transaktion verursacht, ins Roll-Forward-Log
geschrieben, was dazu führen kann, dass Änderungen von Datensätze, die eigentlich korrekt verarbeitbar wären
durch die Verarbeitung eines fehlerhaften Datensatzes letztendlich nicht committet werden können. In diesem
Fall sollte vor dem Roll-Forward die Transaktionsgröße auf „1“ gestellt werden. Damit werden nur mehr jene
Datensätze ins neue Roll-Forward-Log geschrieben, die tatsächlich zu Fehlern führen und man kann sich dann
gezielt um die Behebung der Ursachen dieser Fehler kümmern.
In vielen Fällen ist die Auswahl der Algorithmen zur Vermeidung doppelter Objekte aus Performancegründen
nicht für eine nochmalige Ausführung eines Datenimports und damit auch nicht für die Durchführung eines RollForwards geeignet und muss vor dem Roll-Forward angepasst werden.
87
Ein Roll-Forward darf nur von einem Datenimport verarbeitet werden, bei dem dieselben Spalten in derselben
Reihenfolge verwendet werden, da im Roll-Forward-Log keine Spaltennamen angegeben sind und daher Unterschiede bei der Verwendung nicht erkannt werden können.
5.4
Starten des Datenimports
Das Starten des Datenimports erfolgt gerade in der Entwicklungsphase meistens über das Kontextmenü des
Datenimportobjektes. Damit kann interaktiv der Import angestoßen und der Fortschritt direkt am Bildschirm mitverfolgt werden. Wird der Import im Fabasoft Win32-Client der Version 6 angestoßen, kann man den Datenimport über den Dialog auch abbrechen, was im Fall des Fabasoft Webbrowser-Clients oder des Fabasoft
Windows-Clients nicht möglich ist, da hier der Datenimport am Webserver ausgeführt wird und zu diesem
keine permanente direkte Verbindung besteht.
Doch für die Durchführung größerer Migrationen eignen sich Skripts besser, da hier ganze Abfolgen von Datenimporten, Skripts und evt. auch Datenbankexporten aufgerufen werden können und damit lange dauernde Vorgänge ohne Interaktion und Überwachung ablaufen können. Ein derartiges Skript findet sich im Kapitel „Zusätzliche Beispiele“ auf Seite 159.
Ferngesteuertes Importieren
Für den Aufruf über ein Skript gibt es die Aktion Ferngesteuertes Importieren ([email protected]:
ImportRemote) bei der eine ganze Reihe zusätzlicher Parameter zur Verfügung stehen:
showdialog <BOOLEAN>
Mit diesem Parameter kann man im Fall des Fabasoft Win32-Clients der Version 6 angeben, ob der Fortschrittsdialog angezeigt werden soll oder nicht. Soll der Dialog nicht angezeigt werden, muss dieser Parameter auf
„False“ gesetzt werden. Im Fall der anderen Fabasoft Clients hat der Parameter keine Auswirkungen.
5. Was man unbedingt beachten sollte
5.3 Roll-Forward
5.4 Starten des Datenimports
closedialog <BOOLEAN>
Falls der Fortschrittsdialog angezeigt wird, kann über diesen Parameter gesteuert werden, ob der Dialog nach
der Beendigung des Importvorgangs automatisch geschlossen wird, indem man den Parameter auf den Wert
„True“ setzt, oder ob auf die Bestätigung des Dialogs durch Drücken der Schaltfläche Close gewartet werden
soll.
reportcreatedobjects <BOOLEAN>
Wird dieser Parameter auf „True“ gesetzt, dann wird als Ausgangsparameter createdobjects eine Liste
aller erzeugten Objekte zurückgegeben. Das setzt voraus, dass der Import synchron ausgeführt wird.
createdobjects <OBJECT>
In dieser Objektliste wird die Liste aller erzeugten Objekte zurückgegeben, falls der optionale Parameter
reportcreatedobjects auf „True“ gesetzt wurde.
rollforward <BOOLEAN>
Durch Setzten dieses Parameters auf „True“ werden die Daten nicht von der konfigurierten Datenquelle, sondern
aus dem Roll-Forward-Log, das im Protokollobjekt hinterlegt ist, gelesen.
asynchron <BOOLEAN>
Mit diesem Parameter steuert man, ob der Aufruf der Aktion Ferngesteuertes Importieren
([email protected]:ImportRemote) sofort wieder beendet wird und der eigentliche Datenimport
asynchron in einem eigenen Thread durchgeführt wird („True“), oder ob auf das Ende des Datenimports gewartet werden soll und daher der Aufruf der Aktion erst nach der Beendigung des Datenimportvorganges beendet
wird („False“). Der Datenimport selbst wird jedenfalls in einem eigenen Thread durchgeführt. Für den Datenimport ist es vorteilhaft, wenn durch die Ausführung des Datenimports nicht permanent eine Aktion ausgeführt
wird, da damit Ressourcen nicht freigegeben werden können und der Speicherbedarf höher ist. Andererseits ist
89
es natürlich bei einer Folge von Datenimporten notwendig, das Ende eines Imports abzuwarten bevor der
nächste Import gestartet wird. Das kann sehr effizient durch die Verwendung des im Parameter synchobj
zurückgegebenen COM-Objekts erfolgen.
paramobject: <COMINTERFACE>
Dieses COM-Objekt wird, falls es gesetzt ist, als Kontext an die Skripts übergeben und kann dort zum Beispiel
verwendet werden, um bestimmte Objekte in Objektlisten dieses Objektes zu sammeln. Auch anwendungsspezifische Protokolle können damit realisiert werden.
finishedscript <CONTENT>
Dieses Skript wird nach der Beendigung des Datenimports aufgerufen und kann Nachbearbeitungsschritte eines
Datenimports beinhalten. Einer dieser Schritte kann auch der Start eines weiteren Imports sein. Als globale
Parameter steht neben dem Runtime (coort) und der Transaktion (cootx) auch noch das Objekt des Parameters paramobject als cooparam zur Verfügung. Weiters stehen die Anzahl der verarbeiteten Datensätze (records), die Anzahl der erzeugten Objekte (created), die Anzahl der geänderten Objekte
(refreshed) und die Anzahl der aufgetretenen Fehler (errors) zur Verfügung. Das aufgerufene Datenimportobjekt wird dem Skript als Parameter cooimport übergeben.
synchobj <COMINTERFACE>
Einfacher als mit dem finishedscript kann mit dem syncobj eine Abfolge von Datenimporten,
Datenexporten und anderen Aktionen realisiert werden, indem man den Datenimport mit async gleich „True“
aufruft und danach auf das im Parameter syncobj zurückgegebene Objekt entweder die Funktion Wait aufruft, die auf das Ende des Datenimports wartet, oder periodisch anhand des Resultats der Funktion
IsFinished das Ende des Imports erkennt. Während dieser Zeit kann der Datenimport durch den Aufruf von
Cancel abgebrochen werden.
5. Was man unbedingt beachten sollte
5.4 Starten des Datenimports
table <STRING>
In der Version 7 wurde ein weiterer Parameter eingefügt, um beim Aufruf des Imports die Tabelleneigenschaft
dynamisch überschreiben zu können. Speziell bei Datenquellen, die in der Tabelleneigenschaft den Dateinamen
der Quelldatei beinhalten (zum Beispiel beim Import aus einer CSV-Datei) kann damit beim Aufruf der Dateiname
übergeben werden, ohne das Datenimportobjekt vorher ändern zu müssen.
91
6
93
6 Optimierungen
Bei der Optimierung von Datenmigrationen muss man im ersten Schritt, bevor man an die Umsetzung
oder Optimierung der einzelnen Datenimporte geht, eine Gesamtstruktur erarbeiten. Ein gutes
Design in dieser Phase bewirkt, dass in späteren Phasen durch Skalierung und Parallelisierung
weit bessere Resultate erzielt werden können, als durch einzelne noch so intelligente Optimierungsmöglichkeiten erreicht werden könnte. Datenimporte im Nachhinein umzuschreiben, führt zu
Zeitverlust bei der Entwicklung, und Optimierungsschritte müssen danach oft erneut durchgeführt
werden.
6.1
Struktur des Datenimports
Die Struktur des Datenimports orientiert sich meist an den Abhängigkeiten und Voraussetzungen des Datenmodells und basiert daher auf dem Metadatenkatalog, einer Aufstellung aller im Zielsystem verwendeter
Objektklassen und Eigenschaften. Daraus ergeben sich direkt die Eigenschaften, die in der Ziellösung angezeigt
werden und die daher auch mit Daten zu befüllen sind. Die darin enthaltenen Objektzeigereigenschaften ergeben die möglichen Referenzen zwischen den einzelnen Objektklassen, wobei in der konkreten Lösung meist nicht
alle Möglichkeiten, die das Objektmodell bietet, auch wirklich verwendet werden.
Abhängigkeiten
Aus den Referenzen, die im Metadatenkatalog definiert sind, ergibt sich implizit eine Reihenfolge der Importe.
Diese ist jedoch nicht linear zu sehen, sondern viel mehr als eine Liste voneinander abhängiger Einzelschritte,
wie man sie in einer Projektplanung kennt und dort oft als Balkendiagramm darstellt. Schätzt man die Zeiten für
die einzelnen Vorgänge ab und setzt die verwendeten Ressourcen ein, so kommt man schnell zu einem kritischen
Pfad, der die Dauer der gesamten Migration definiert.
Wie kommt man aber nun zu den Abhängigkeiten und wie kann man diese auflösen?
Voraussetzungen
Einerseits gibt es Abhängigkeiten, die durch eine Referenz auf eine andere Objektklasse gegeben sind, die beim
Erzeugen des Objekts bereits gesetzt werden muss. Es wird also der vollständige Import von Objekten einer Klasse A für den Import der Objekte der Klasse B vorausgesetzt. Zum Beispiel müssen die Sachgebiete bereits definiert sein, bevor Sachakten angelegt werden können, da es in der Anwendungslogik nicht vorgesehen ist, dass
Sachakten existieren, die keinem Sachgebiet zugeordnet sind. Genauso ist es unbedingt notwendig, dass jene
Objekte, die in die Objektliste eines Ordners gelegt werden sollen, zuvor angelegt werden, bevor sie in den Ordner gelegt werden können. Es ergibt sich also eine zwingende Reihenfolge der Datenimporte.
Referenzen
Objekte, die einander referenzieren – also in Objektzeigereigenschaften einer anderen Objektklasse enthalten
sind – können jedoch oft auch unabhängig voneinander angelegt und im Nachhinein verknüpft werden.
Beispiel: Import von Organisationen und Personen
Es sollen Organisationen und Personen angelegt werden, wobei jede Person als Ansprechpartner in einer
Organisation einzutragen ist. Es kann pro Organisation auch mehrere Ansprechpartner geben.
Es gibt jetzt drei mögliche Strukturierungen für diesen Datenimport:
1. Alle Datensätze werden mit einem einzigen Datenimport geladen.
Das ist in vielen Fällen eine sehr effiziente Variante, da hier die wenigsten Updates erfolgen, allerdings
hat sie den Nachteil, dass die Komplexität steigt, wenn auch an anderen Stellen der Migration Organisationen oder Personen angelegt werden.
2. Organisationen werden zuerst geladen und beim Laden der Personen wird auch die Beziehung zwischen
der Organisation und der Person erstellt.
Hier werden die Objektklassen sauber getrennt, doch das vollständige Laden der Organisationen ist eine
6 Optimierungen
6.1 Struktur des Datenimports
Voraussetzung für das Laden der Personen und damit müssen die beiden Importe hintereinander durchgeführt werden.
3. Organisationen und Personen werden in eigenen Datenimporten angelegt und die Verbindung zwischen
den beiden Objektklassen in einem eigenen Import erstellt.
Die Objekte beider Objektklassen können nun unabhängig voneinander geladen werden. Das Erstellen
der Verbindung zwischen den zwei Objektklassen setzt jedoch den vollständigen Import aller Objekte
beider Objektklassen voraus.
Je mehr Beziehungen als Voraussetzungen gelten, desto stärker sind die Einschränkungen im Bezug auf die Reihenfolge der Importe und damit auch auf die Parallelisierbarkeit. Für ein gut parallelisierbares Design ist es
daher notwendig, direkte Voraussetzungen zu vermeiden und Referenzen erst später setzen zu können.
Hintergrund: Konkretes Migrationsszenario
Bei einer kürzlich optimierten Datenübernahme gab es zwei zentrale Objektklassen, von denen jeweils noch
drei bzw. vier Objektklassen abhängig waren. Die beiden zentralen Klassen waren über einen bidirektionalen Link verbunden. In der Originalimplementierung wurden die Objekte der einen Objektklasse importiert
und danach, beim Importieren der zweiten Objektklasse, wurde der Link auf die erste Objektklasse gesetzt.
Von beiden Objektklassen mussten mehrere Millionen Objekte erzeugt werden. Allein diese beiden Importe überschritten die zur Verfügung stehende Migrationsdauer.
Diese Abhängigkeit wurde dahingehend aufgelöst, dass die Objekte der beiden Objektklassen parallel
angelegt wurden und erst in einem neuen, späteren Importvorgang verknüpft wurden. Die wichtigste Voraussetzung dafür war eine effiziente Suche nach den angelegten Objektinstanzen. Diese wurde über einen
Datenbankexport und einen JOIN auf der Quelldatenbank realisiert. Trotz des Mehraufwands eines
zusätzlichen Imports und der Datenbankexporte war der Import allein dadurch viel schneller als in der Originalimplementierung.
95
Wie man aus diesem Beispiel sieht, sind es besonders die Objektklassen mit einer hohen Anzahl von Objekten,
die hierbei einer Rolle spielen. Bei Objektklassen mit wenigen 100 Instanzen lohnt sich meistens der Aufwand
der Optimierung nicht.
Migrationszwischenformat
Einen ersten Ansatz für eine Strukturierung der Datenimporte bietet das so genannte Migrationszwischenformat. Nach einfachen Regeln werden aus dem Metadatenkatalog pro Objektklasse zwei Importe abgeleitet
(oder sogar generiert). Der erste Import erzeugt die Objekte der Objektklasse und setzt so viele Eigenschaften
wie möglich. Ausnahmen sind Objektzeiger, die Objekte referenzieren, die zum Zeitpunkt des Imports noch nicht
erzeugt wurden, und Listeneigenschaften. Diese ausständigen Eigenschaften werden später mit dem zweiten
Datenimport befüllt. Darüber hinaus kann es für manche Objektklassen oder Eigenschaften spezielle Importe
geben. Diese sind zum Beispiel notwendig um Schlüssel-Nummeratoren zu setzen oder um spezielle Eigenschaften bei mehreren Objektklassen zu laden. Typische Beispiele dafür sind Manuelle Unterschriften oder Benutzer/Gruppen mit Änderungsberechtigungen.
Durch die direkte Ableitung der Importe aus dem Metadatenkatalog ist die Struktur der Datenimporte einfach
durchschaubar und durch den Metadatenkatalog bereits zu einem guten Teil dokumentiert. Es kann daraus direkt
eine Datenbankdefinition abgeleitet werden, die als Grundlage für eine organisatorische Aufteilung der Migrationsentwicklung verwendet werden kann. In einigen Migrationen wurden die Tabellen des Zwischenformats
vom Auftraggeber oder einer von diesem beauftragten Drittfirma mit den Daten aus dem Altsystem befüllt und
der Datenimport aus dem Zwischenformat von Fabasoft Consultants umgesetzt.
Die organisatorischen Vorteile dieser Vorgehensweise und auch die Reduktion der Komplexität überwiegen oft
den dadurch entstehenden Mehraufwand durch die höhere Anzahl von einzelnen Datenimporten. Falls notwendig können aber auch auf Basis der Tabellen weiter optimierte Importe abgeleitet werden, die als Datenbasis
dann eine View auf mehrere Tabellen des Zwischenformats verwenden.
6 Optimierungen
6.1 Struktur des Datenimports
6.2 Optimierungsoptionen des Imports
Zusammenfassen von Importen
Das Zusammenfassen von Importen macht vor allem beim Import von mehreren Objektklassen Sinn, die über
einen Objektzeiger verbunden sind und deren Anzahl relativ gleich ist (1:1-Beziehung oder 1:n-Beziehung mit
kleinem n). Damit kann durch den gemeinsamen Import ein späteres Update der Objekte vermieden werden. Das
wirkt sich insofern besonders stark aus, dass Updates wesentlich aufwendiger sind, als das Setzen der Eigenschaft in der Transaktion, in der das Objekt erzeugt wird.
Aufteilung von Importen
Gerade den gegenteiligen Schritt muss man oft setzen, wenn man die Migration auf Parallelisierung optimiert.
Dann kann es durchaus Sinn machen, unterschiedliche Updates auf mehrere Importe aufzuteilen, die dann entweder parallel oder aber in verschiedenen Phasen des Imports durchgeführt werden, um so den Ablauf der
Migration zu optimieren.
6.2
Optimierungsoptionen des Imports
Es gibt viele Ansatzpunkte für Optimierungen. Die wichtigsten davon hängen direkt mit der Konfiguration der
Datenimportobjekte zusammen. Hier kann man die meiste Performance verlieren oder gewinnen. In Abbildung
16 sind die wichtigsten Punkte zusammengefasst, die man als Checkliste für die Optimierung verwenden kann.
97
Abbildung 16
Optimierungsoptionen des
Datenimports
Algorithmen zur Vermeidung doppelter Objekte
Optimiert man einen Datenimport, so fängt man generell mit der Auswahl der Schlüsseleigenschaften und der
Suchmethoden an. Hier kann man durch die Einhaltung einiger weniger Regeln die richtige Methode auswählen. Die einzelnen Methoden sind im Kapitel „Identifikation und Duplikatsprüfung“ auf Seite 55 ausführlich mit
ihren Vor- und Nachteilen aufgelistet.
Wichtig bei der Optimierung ist auch, dass bei Algorithmen, die die Suche auf der Datenbank verwenden, auch
entsprechende Indizes definiert sind, sodass die Datenbank die Suche effizient durchführen kann. Ein häufiger
Fehler dabei ist, dass während der Entwicklung der Migration nur mit Testdatenbeständen gearbeitet wird, die
nur einen Bruchteil der Echtdaten umfassen und dadurch Performanceprobleme, die erst bei weiterer Befüllung
der Datenbank auftreten, nicht erkannt werden. Wird in einer fast leeren Datenbank bei der Suche ein Tablescan
6 Optimierungen
6.2 Optimierungsoptionen des Imports
gemacht, fällt das kaum auf. Läuft derselbe Import aber über eine Million Datensätze, dann ist ein Tablescan bei
der Suche nicht mehr vertretbar. In diesem Fall helfen die Werkzeuge der Datenbanken bei der Optimierung der
Indizes. Dabei darf aber nicht übersehen werden, dass jeder Index auch bei Datenänderungen (INSERT,
UPDATE oder DELETE) angepasst werden muss, also auf der Datenbank Last verursacht. Daher ist es gut,
Indizes, die während der Migration nicht verwendet werden, vor der Migration zu löschen und danach wieder
anzulegen. Die primären Indizes dürfen jedoch nicht gelöscht werden, da sie einerseits beim Laden der Objekte
in den Cache benötigt werden und andererseits – wie die Clustered Indizes beim SQL-Server – auch die Art der
Speicherung der Werte angeben.
Sortierung
Einen nicht zu unterschätzenden Einfluss auf die Performance des Imports hat die Sortierung der Datensätze. In
vielen Fällen werden Objektlisten befüllt, was effizienter erfolgen kann, wenn Änderungen eines Objektes in
einer einzigen Transaktion zusammengefasst werden, als wenn diese über den gesamten Import verteilt werden.
Pro Transaktion wird bei jedem geänderten Objekt neben der eigentlichen Änderung auch zumindest das Änderungsdatum angepasst, was durch das Zusammenfassen von Änderungen entsprechend seltener durchgeführt
werden muss. Zudem ist auch das Caching auf allen Ebenen, von der Datenbank über das Fabasoft Components
COO-Service bis zum Kernel-Cache, effizienter, wenn die Verwendung von Objekten zeitlich begrenzt ist und
daher diese Objekte auch wieder aus dem Cache entfernt werden können, ohne sofort wieder geladen werden
zu müssen.
Gruppenwechsel
Der Gruppenwechsel optimiert die Verarbeitung sortierter Datenbestände noch weiter, indem die Änderungen,
die ein bestimmtes Objekt betreffen, innerhalb einer einzigen Transaktion durchgeführt werden können. Neben
den Performancevorteilen ist das auch eine Voraussetzung für die Parallelisierung, da Änderungen, die ein und
dasselbe Objekt betreffen, zu jedem Zeitpunkt nur von einer einzigen Transaktion gemacht werden dürfen.
Werden für einzelne Objekte dennoch mehrere Transaktionen benötigt, schützt im Normalfall der interne
Sperrmechanismus der Datenimporte vor inkonsistenten Änderungen indem ein Worker Thread solange
99
angehalten wird, bis alle zu ändernden Objekte nicht mehr an Transaktionen anderer Worker Threads beteiligt
sind.
Transaktionsgröße
Die Transaktionsgröße, die durch die Anzahl der Datensätze pro Commit bestimmt wird, hat weniger Bedeutung
für die Performance. Bei Verwendung des Gruppenwechsels sollte sie größer als die maximale Anzahl von
Datensätzen pro Objekt sein, wobei sie auch dort nur in Ausnahmefällen über 1.000 liegen sollte. Die optimale
Transaktionsgröße ergibt sich aus einem Kompromiss zwischen der Ressourcenbelegung, die bei großen Transaktionen zunimmt, und dem Transaktions-Overhead der durch viele kleine Transaktionen verursacht wird.
Ein nicht zu vernachlässigender Faktor ist die Verzögerung der Datenbank beim Schreiben der Logs auf die Festplatten, denn das Schreiben muss synchron mit dem Commit erfolgen.
Hintergrund: Rechenbeispiel
Wenn man bei den aktuellen Festplatten von ca. acht Millisekunden durchschnittlicher Zugriffszeit ausgeht,
so wird allein dadurch die Anzahl der sequenziellen Transaktionen pro Sekunde auf ca. 120 begrenzt. Würde man nur einen Datensatz pro Transaktion importieren, könnte man damit gerade einmal 7.000 Datensätze pro Minute verarbeiten. Aber schon mit einer Transaktionsgröße von 24 Datensätzen könnte man – gäbe
es nur dieses Limit – 10 Mio. Datensätze in der Stunde verarbeiten.
Eine kurze Testreihe auf einem einzelnen Server hat bei einem konkreten Import eine optimale Einstellung
von 64 Datensätzen pro Commit ergeben, wobei die gemessenen Werte zwischen 16 Datensätzen und
1.024 Datensätzen sich um weniger als 10 % unterschieden haben.
6 Optimierungen
6.2 Optimierungsoptionen des Imports
Parallelisierung
Es gibt drei verschiedene Ansätze, wie Parallelisierung erreicht werden kann
°
°
°
Verwendung von mehreren Threads
Verteilung der Datensätze eines Imports auf mehrere Clients (Fabasoft Components Kernels).
Parallele Durchführung mehrerer verschiedene Importe
Die einfachste und ungefährlichste Art zur Parallelisierung eines Datenimports ist die Verwendung von Threads.
Diese Vorgehensweise hat jedoch auch das geringste Potential. Dabei werden mehrere Datenpakete gleichzeitig auf demselben Fabasoft Components Kernel verarbeitet. In diesem Fall werden jene Zeiten, in denen der
Fabasoft Components Kernel nicht von einem Worker Thread belegt wird, von anderen Worker Threads genutzt.
Vor allem sind das jene Zeiten, in denen RPCs auf die Fabasoft Components Backendservices gemacht werden,
um Suchen durchzuführen, Objekte zu laden oder die Transaktionen zu committen. Die Anwendungslogik, die
ebenfalls Zeit außerhalb des Fabasoft Components Kernels verbraucht, wird im Allgemeinen bei Datenimporten
auf das Notwendigste reduziert und spielt im Verhältnis zum Kernel-Anteil nur eine untergeordnete Rolle.
Um das Problem der Limitierung des Fabasoft Components Kernels zu umgehen kann man den Import auch auf
mehrere Fabasoft Components Kernels verteilen, jedoch kann die Verteilung nicht mehr automatisch erfolgen,
wie bei den Threads, sondern muss manuell konfiguriert werden. Voraussetzung dafür ist jedoch, dass die einzelnen Datenpakete komplett unabhängig voneinander importierbar sind und so aufgeteilt werden, dass gleichzeitige Änderungen an referenzierten Objekten von mehreren Fabasoft Components Kernels ausgeschlossen
werden können. Mit dieser Methode kann auf Seite der Clients gut skaliert werden. In einer konkreten Migration wurden die Daten dafür in 16 Pakete geteilt, die parallel geladen wurden. Damit war – obwohl auf den
Clients noch einiges an Anwendungslogik aktiv war – die Datenbank für einige Stunden voll ausgelastet. Bei
einer derartigen Aufteilung steigt auch der Verwaltungsaufwand erheblich, der zum Starten, Überwachen und
auch für die Koordination der Synchronisationspunkte der jeweiligen Importabfolgen auf den einzelnen Clients
notwendig ist.
101
Weniger Zusatzaufwand ergibt sich durch das parallele Starten voneinander unabhängiger Importe auf unterschiedlichen Clients oder Fabasoft Components Kernels. Dabei sind jedoch die Abhängigkeiten zu berücksichtigen, die teilweise in den Methoden der Anwendungslogik, aber auch in den Konfigurationen versteckt sein können. Daher setzt diese Art der Parallelisierung eine genaue Kenntnis der Lösung voraus. Außerdem beschränkt
sich die Anzahl der parallel durchführbaren Datenimporte oft auf wenige Objektklassen. Manchmal kann man
jedoch Abhängigkeiten durch zusätzliche Importe auflösen, wie das schon im Rahmen der „Struktur des Imports“
dargelegt wurde.
6.3
Client-Optimierung
Unabhängig von den Einstellungen des Datenimports gibt es einige wenige Aspekte, die am Fabasoft Components Kernel (je nachdem von wo man die Daten importiert am Fabasoft Win32-Client der Version 6, am Weboder am AT-Server) beachtet werden sollten.
Client-Cache
Der Client-Cache ist für jeden Datenimport eine kritische Ressource. Für den Cache ist ein Datenimport eine
Extremsituation, da mit einer sehr hohen Geschwindigkeit immer neue Objekte erzeugt, geändert oder gespeichert werden. Bei ausreichend großen Datenimporten wird der Cache vollständig durch den Datenimport definiert, wodurch auf Webservern das Arbeiten anderer Benutzer stark beeinträchtigt wird.
Der im Cache-Limit angegebene Wert (die Defaulteinstellung ist 20.000 Objekte und lässt sich über die Arbeitsumgebung ändern) ist nur ein Richtwert. Je nachdem, wie das Verhältnis zwischen der Anzahl der Objekte im
Cache zur konfigurierten Cachegröße ist, wird der Cache mehr oder weniger oft aufgeräumt. Ist also der Cache
zuerst nur mäßig befüllt und startet ein Import mit einer großen Geschwindigkeit, kann es durchaus passieren,
dass der Client-Cache ein Vielfaches seiner konfigurierten Größe erreicht, bis der Aufräumprozess beginnt die
Objekte wieder aus dem Cache zu entfernen. Das ist aber kein Grund zur Besorgnis, darauf ist der Fabasoft
Components Kernel ausgelegt und mit dieser Situation kommt er gut zurecht, solange dabei nicht die Größe des
physischen Speichers erreicht wird und das System anfängt Daten auf die Auslagerungsdatei zu schreiben.
6 Optimierungen
6.2 Optimierungsoptionen des Imports
6.3 Client-Optimierung
Kritisch wird es auf 32-Bit-Systemen jedenfalls, wenn die Prozessgröße den Bereich der maximalen Prozessgröße von zwei bzw. drei Gigabyte erreicht.
Der Aufräumprozess des Clients hatte vor der Version 7 auch noch eine weitere Einschränkung: Er konnte nicht
arbeiten, solange Aktionen im Fabasoft Components Kernel aufgerufen wurden. Öffnet man am Fabasoft Win32Client der Version 6 ein Objekt zum Bearbeiten, dann wird dadurch eine Aktion aufgerufen, die erst mit dem
Schließen des Fensters wieder verlassen wird. Läuft gleichzeitig ein Datenimport, so steigt die Anzahl der
Objekte im Cache permanent an, bis das Fenster zur Bearbeitung des Objekts geschlossen wird, der Datenimport fertig ist oder die Speichergrenze erreicht ist. Letzteres führt häufig zum Absturz des Clients. Daher durfte
man bis Version 6 auch nicht größere Datenimporte über die Aktion Ferngesteuertes Importieren
([email protected]:ImportRemote) synchron starten. Der Start der Aktion allein reichte aus, dass der
Cache nicht mehr aufgeräumt werden konnte. Daher musste der Import über ein Skript aus dem Betriebssystem
aufgerufen und der Parameter async auf „True“ gesetzt werden. Dann gab es verschiedene Möglichkeiten
festzustellen, ob der Datenimport bereits fertig ist. Im Anhang befindet sich ein Skript, das sequenziell mehrere
Datenimporte verarbeitet.
In Version 7 wird der Cache auch aufgeräumt, wenn ein Fenster geöffnet ist, daher ist es dort kein Problem mehr,
Datenimporte synchron zu starten.
Welche Werte für die Cachegröße effizient sind, hängt davon ab, wie man gerade importiert. Legt man beispielsweise mit jedem Datensatz ein Objekt an, das im Import nicht wieder verwendet wird, so werden die Informationen im Cache nicht wieder verwendet und sind somit überflüssig. Eine große Cachegröße hat in diesem Fall
nur die Auswirkungen, dass der Speicherverbrauch höher ist und der Zugriff auf den großen Cache langsamer
ist, als bei einem kleinen Cache. Werden jedoch beim Import Objekte immer wieder verwendet, verändert oder
referenziert, dann hilft der Cache bei der Vermeidung von unnötigen Ladevorgängen.
Netzwerkanbindung
Die performante Anbindung der Clients ist eine Grundvoraussetzung für einen schnellen Datenimport. Während
die Bandbreite dabei nur beim Laden von Inhalten ausschlaggebend ist, wirkt sich die Netzwerkverzögerung
103
direkt auf die Kommunikation zwischen Fabasoft Components Kernel und Fabasoft Components COO-Services
aus, die durch eine hohe Anzahl von Roundtrips charakterisiert ist. Daher sollten sich die Migrationsclients und
die Fabasoft Components Backendserver im gleichen LAN befinden und nicht über WAN-Strecken vernetzt sein.
Es sollten sich auch keinesfalls Firewalls zwischen den Clients und den Fabasoft Components Backendservern
befinden.
Client-CPUs
Es liegt auf der Hand, dass die Performance eines Datenimports von schnellen CPUs am Client profitiert, denn
oft ist es die Client-CPU, die stark ausgelastet und daher die kritische Ressource des Datenimports ist.
Ein Multiprozessorsystem kann erst bei der Verwendung von mehreren Threads oder mehreren Importen auf
einem Client Vorteile bringen. Einschränkend wirkt da der Fabasoft Components Kernel, der keine parallele Verarbeitung von Kernel-Methoden zulässt. Damit ist das Potential für eine Parallelisierung innerhalb eines Prozesses eher gering und beschränkt sich vor allem auf die Ausnützung der RPC-Zeiten durch andere Threads. Eine
echte Verwendung von mehreren Prozessoren kann auch beim Datenimport derzeit nur durch das Starten von
mehreren Fabasoft Components Kernels auf einem Client erreicht werden.
Festplatte
Die Festplatte des Client-Rechners wird beim Import von Inhalten stark belastet, denn alle Inhalte werden zuerst
in das DOCDIR-Verzeichnis der lokalen Festplatte kopiert und von dort erst wieder entfernt, wenn das Inhaltsobjekt aus dem Client-Cache entfernt wird. Hat man also bei einem derartigen Import einen Cache mit 20.000
Objekten konfiguriert, dann liegen potenziell mehr als 20.000 Inhalte im DOCDIR, also möglicherweise mehrere Gigabyte. Alle diese Dateien müssen auch erst einmal dorthin geschrieben werden. Eine schnelle Festplatte
wirkt sich daher beim Import von Inhalten direkt auf die Performance des Imports aus. Kritisch ist jedenfalls die
Verwendung von Virenscannern, die im laufenden Betrieb alle Dateien scannen, auf die zugegriffen wird. Das
führt zu wesentlichen Performanceeinbußen beim Import.
6 Optimierungen
6.3 Client-Optimierung
6.4 Fabasoft Components COO-Service-Optimierung
Anzahl der Clients
Eine wichtige Maßnahme bei der Implementierung von großen Datenmigrationen ist die Parallelisierung der
Datenimporte auf mehreren Clients. Hier lässt sich durch Hardwareeinsatz eine Vervielfachung des Durchsatzes
erreichen, was allerdings mit entsprechenden Kosten und mit einigem Aufwand bei der Parallelisierung und der
Durchführung der Migration verbunden ist.
6.4
Fabasoft Components COO-Service-Optimierung
Die Fabasoft Components COO-Services als Schnittstelle zwischen Client und Datenbank haben vor allem die
Aufgabe, Objekte zu cachen und für das Laden und Speichern der Daten in die Datenbank zu sorgen. Dabei sollten drei Aspekte berücksichtigt werden – die Anzahl der Worker Threads, die Cache-Einstellungen und Objektsperren.
Anzahl der Worker Threads
Eine wichtige Voraussetzung für einen effizienten Import ist die korrekte Einstellung der Anzahl der Worker
Threads. Stehen weniger Threads zur Verfügung, als benötigt werden, so müssen ankommende RPCs warten,
bis wieder ein Thread frei geworden ist. Nachdem aber ein Datenimport nicht warten soll, muss gewährleistet
sein, dass immer ausreichend viele Threads verwendbar sind. Ein Datenimport benötigt auf jenen Services, die
vom Import betroffen sind, maximal so viele aktive Backend Threads wie im Datenimport Worker Threads definiert sind. Außerdem werden während der Initialisierung beim Sammeln von Schlüsseln für jede zu sammelnde
Objektklasse zwei Threads auf den jeweiligen Services benötigt. Multipliziert man diesen Wert mit der Anzahl
der parallelen Datenimporte kommt man auf einen Richtwert, der jedenfalls ausreichend ist. Zusätzlich muss am
primären Fabasoft Components COO-Service für jeden parallelen Datenimport ein Worker Thread zur Verfügung
stehen.
105
Berechnungsbeispiel
Folgender Import ist definiert:
°
°
°
°
°
Es werden Personen und Organisationen in getrennten Datenimporten erzeugt.
Über die Objektplatzierung ist festgelegt, dass jede Objektklasse ein eigenes Service verwendet.
Es wird die „Suche für jedes Objekt“ verwendet.
Pro Datenimport sind vier Threads eingestellt.
Auf jedem der drei Clients werden ein Personenimport und ein Organisationenimport gestartet.
Damit braucht man auf den betroffenen Services für jeden der drei Clients mindestens vier Threads für die
vier Worker Threads des Imports, was einen Wert von je zwölf Threads pro Fabasoft Components COO-Service und auf dem primären Fabasoft Components COO-Service auch zumindest sechs Threads allein für den
Datenimport ergibt.
Bei höherer Parallelisierung können entsprechend hohe Werte erreicht werden.
Die eigentliche Auswirkung der Worker Threads am Fabasoft Components COO-Service ist jedoch, dass jeder
Thread, sobald er einmal verwendet wird, eine Datenbankverbindung öffnet und im Normalfall nicht mehr freigibt. Damit hat die Erhöhung der Worker Threads auf dem Fabasoft Components COO-Service eine direkte Auswirkung auf den Ressourceverbrauch der Datenbank, da auch hier mehr Sessions geöffnet werden. Daher muss
vor der Erhöhung des Werts abgeklärt werden, ob die gewünschte Anzahl von Sessions überhaupt auf der Datenbank unterstützt ist (zwei Sessions pro Fabasoft Components COO-Service sollten zusätzlich eingerechnet werden). Sonst kann es sein, dass mitten in der Migration, wenn die maximale Anzahl der Sessions auf der Datenbank erreicht ist, viele Fehler auftreten und man unter Umständen viel Zeit durch ein Restore oder durch die Fehlerbehebung verliert.
6 Optimierungen
6.4 Fabasoft Components COO-Service-Optimierung
6.5 Optimierungen am Datenbanksystem
Fabasoft Components COO-Service-Cache
Beim Cache am Fabasoft Components COO-Service ist die Situation ähnlich wie beim Client-Cache. Auch hier
profitiert die Migration nur dann vom Cache, wenn dieser so groß ist, dass Objekte wiederverwendet werden,
bevor sie aus dem Cache herausfallen. Nimmt man zum Beispiel die Situation her, dass zuerst alle Objekte einer
Objektklassem mit 100.000 Instanzen angelegt werden und im nächsten Schritt Updates auf diese Objekte
gemacht werden, so muss diese Objektmenge komplett im Cache Platz finden, damit dieser effizient arbeiten
kann. Bis Version 6.1 wird dabei die Anzahl der Objekte im Cache spezifiziert und – wie beim Client-Cache – als
Richtwert für den Aufräumprozess verwendet. Also auch hier kann der Maximalwert den Richtwert deutlich
überschreiten. In Version 7 wird hingegen der maximal verwendete Speicherplatz definiert und zudem die Speicherung optimiert, sodass im Endeffekt mehr Objekte im Cache gehalten werden können und keine Gefahr mehr
besteht, dass das Fabasoft Components COO-Service beim Erreichen der Speichergrenzen abstürzt.
Objektsperren
Objektsperren werden im Normalbetrieb in der Tabelle cooobjlock2 abgespeichert. Beim Sperren wird für
jedes Objekt einzeln ein INSERT in diese Tabelle durchgeführt. Das bedeutet, dass für jede Sperre eine Transaktion auf der Datenbank ausgeführt wird. Durch das Setzen eines Registry-Eintrags werden die Sperren nicht
mehr in die Datenbank geschrieben, sondern nur am Fabasoft Components COO-Service im Speicher gehalten.
Das ist natürlich wesentlich schneller, hat aber den Nachteil, dass bei einem Neustart des Fabasoft Components
COO-Services diese Information verloren geht. Im Fall einer Migration ist dieses Risiko jedoch kalkulierbar, da
ein Neustart des Fabasoft Components COO-Services nur kontrolliert erfolgt und im Offline-Betrieb keine Sperren von Benutzern gehalten werden.
6.5
Optimierungen am Datenbanksystem
Die Optimierung von Datenbanksystemen wird von vielen Experten fast wie eine eigene Wissenschaft betrieben. In diesem Kapitel werden nur jene Eckpunkte erläutert, die speziell für den Betrieb von Fabasoft Components Domänen im Rahmen von Datenmigrationen wichtig sind.
107
Backup, Restore und Recovery
Große Datenmigrationen sollen, wenn das organisatorisch möglich ist, offline durchgeführt werden, also ohne
gleichzeitigen Produktionsbetrieb.
Jede Migration beginnt mit einem Backup des kompletten Datenbestandes, damit bei unvorhergesehenen Problemen auf einen gesicherten Stand zurückgesetzt werden kann. Auch am Ende jeder Migration steht ein
Backup, damit man, falls ein Systemfehler auftritt, nicht alle Änderungen der Migration wiederholen muss. Das
bedeutet aber, dass alle Datenbank-Logs die zwischen diesen beiden Backups anfallen, nur für das Recovery
innerhalb der Migrationsphase relevant sind und da sind Zwischenbackups an definierten Synchronisationspunkten meistens die einzige Möglichkeit, einen konsistenten Stand sichern zu können. Die Datenbank-Logs sind also
für ein Recovery unerheblich und müssen daher nicht gesichert werden, was erheblich Speicherplatz einspart.
Am Microsoft SQL-Server kann man dafür das Recovery-Model der betroffenen Datenbanken auf „Simple“
stellen. In Oracle kann man die Archivierung der Redo-Logfiles in dieser Zeit deaktivieren.
Indizes und Statistiken
Indizes sind Datenstrukturen, über die man performant nach Daten suchen kann. Doch sie sind nur dann performant, wenn sie auch wirklich verwendet werden. Bei einer Datenmigration werden zwei Arten von Indizes verwendet:
1. Die Indizes der Primärschlüssel
Diese Indizes, die von Fabasoft Components mit dem Tabellennamen erweitert um „PK“ benannt werden, garantieren einerseits ein gewisses Maß an Datenkonsistenz und werden andererseits beim Laden der Objektinformationen aus der Datenbank benötigt. Diese Indizes dürfen daher in keinem Fall geändert oder deaktiviert werden.
6 Optimierungen
6.5 Optimierungen am Datenbanksystem
2. Die Indizes für die Suche nach Objekten
Für das Sammeln von Schlüsseln und für die Suche nach einzelnen Objekten werden Queries abgesetzt. Im ersten Fall nach Objekten einer oder mehrerer Objektklassen, im anderen Fall nach den entsprechenden Schlüsselwerten. Beide Arten von Queries kann man mit Indizes optimieren. Welche das sind, hängt nicht zuletzt vom verwendeten Datenbanksystem ab, das in der Regel genau zu diesem Zweck eigene Tools anbietet, mit denen man
diese Queries aufzeichnen und optimieren kann.
Im Microsoft SQL-Server gibt es dafür den Profiler, der eine Session aufzeichnet und den Database Engine
Tuning Advisor, der die abgesetzten SQL-Statements analysiert und Vorschläge für Indizes errechnet.
Bei Oracle sind diese Funktionen im Enterprise Manager integriert, bei dem man einfach die einzelnen SQLStatements auswählen kann, für die dann Optimierungsvorschläge generiert werden.
Diese Vorschläge für Indizes enthalten in der Regel genau die Spalten, nach denen gesucht wird, und möglicherweise noch die Objektadressen. Verwendet man diese Indizes, hat man meistens schon die Optimierung auf der
Datenbank durchgeführt.
Alle zusätzlichen Indizes, die zum Beispiel für häufige Suchen im Produktivbetrieb definiert wurden, behindern
die Datenmigration und sollten zuvor unbedingt gelöscht werden. Der Neuaufbau dieser Indizes nach der Migration ist wesentlich effizienter als das permanente Mitführen der Indizes während der Migration.
Eine wesentliche Information für die Verwendung von Indizes sind die Statistiken. Diese werden für die korrekte Optimierung der Zugriffspläne benötigt. Je nach Datenbank und Konfiguration wird die Berechnung der Statistiken automatisch durchgeführt oder muss manuell angestoßen werden. Gerade wenn man einen Initialimport
durchführt, muss man darauf achten, dass die Statistiken regelmäßig aktualisiert werden, da erst dadurch die
besten Zugriffspfade verwendet werden können.
109
Beispiel: Auswirkungen von Statistiken
Bei der Optimierung einer Datenmigration auf Oracle wurde durch einige wenige Indizes die Durchlaufzeit
um 60 % reduziert, ohne die Migration selbst anzugreifen. Die Optimierung wurde aber erst wirksam, wenn
man die Statistiken nach ca. 10 % der Migrationszeit neu berechnete, da bis dorthin die Statistiken verwendet wurden, die auf den ursprünglich leeren Tabellen basierten. Um die Berechnung der Statistiken
während der Laufzeit zu vermeiden, wurden schlussendlich vor der Migration Backups der Statistiken eingespielt, die nach einem Testlauf gezogen wurden und daher von vornherein jene Zugriffstrategie ausgewählt wurde, die bei einer befüllten Datenbank ideal ist.
Tabellendefinitionen
Fabasoft Components implementiert zur Speicherung der Objekte ein generisches Datenmodell, das auf der
Datenbank eigentlich in sieben Tabellen passt, pro Wertetyp eine und eine zusätzliche für die zusammengesetzten Eigenschaften.
°
°
°
°
°
°
°
atstrval
atintval
atdateval
atcontval
atobjval
atfloval
ataggval
Vom System werden bereits Tabellen definiert, die für eine weniger generische aber dafür effizientere Speicherung sorgen. Die Tabellen cooobject, cooversion und coocontent beinhalten einige Eigenschaf-
6 Optimierungen
6.5 Optimierungen am Datenbanksystem
ten der Objektklasse Objekt und der Inhalte. Derartige Tabellen lassen sich aber auch lösungsspezifisch definieren und haben mehrere Vor- und Nachteile:
Vorteile:
°
Effizientere Speicherung: In den generischen Tabellen wird mit jedem Wert die objid, attrid,
aggrid und lineid mitgespeichert. Das sind also 24 Byte Information, um den Wert zu identifizieren.
In einer Tabelle, in der ja mehrere Werte zusammengefasst sind, wird pro Zeile nur die objid und bei
Tabellen für zusammengesetzte Eigenschaften noch die aggrid gespeichert. Die attrid ist implizit
durch die Datenbankspalte definiert und die lineid ist implizit definiert, da die Tabellen keine Listen enthalten können.
°
Bessere Indizierbarkeit: Will man in diesen Tabellen effizient suchen, so benötigt man Indizes darauf. Diese
Indizes sind wesentlich kleiner und somit schneller als die Indizes auf den generischen Tabellen. Zudem kann
man auch mehrspaltige Indizes definieren. Wenn also zum Beispiel bei Personen häufig nach Vor- und Nachname gesucht wird, dann kann man dafür einen gemeinsamen Index auf der Tabelle anlegen.
°
Entlastung der generischen Tabellen: Bei großen Installationen können die generischen Tabellen sehr stark
anwachsen, möglicherweise auf mehrere hundert Millionen Datensätze. Dadurch werden aber auch die
Operationen auf diesen Daten immer ineffizienter. Durch die Definition einer eigenen Tabelle für zum Beispiel 50 Werte lassen sich mit einem Datensatz in der neuen Tabelle bis zu 50 Werte aus den generischen
Tabellen entfernen, wodurch diese wieder deutlich kleiner und damit performanter werden.
Nachteile:
°
Verwendbarkeit: Listeneigenschaften (mit Ausnahmen von kleinen Zeichenkettenlisten) können nicht in
eigenen Tabellen abgelegt werden.
°
Indizierung: Alle Eigenschaften, nach denen gesucht wird, müssen eigens indiziert werden, was einen
erhöhten Verwaltungsaufwand bedeutet. Die Größe der notwendigen Indizes ist jedoch generell kleiner als
bei der Verwendung der generischen Tabellen.
111
°
Beim Laden von Objekten aus der Datenbank müssen diese Tabellen zusätzlich gelesen werden. Das ergibt
zusätzliche SQL-Statements.
Die Definition von Tabellen kann bei der Datenmigration geringfügig Zeit sparen, speziell wenn es darum geht
das Workingset der Datenbank klein zu halten oder eine Schlüsselsuche zu optimieren. Wichtig ist aber vielmehr,
die Tabellen bereits vor der Migration zu definieren, da der nachträgliche Aufbau der Tabellen sehr zeitaufwändig ist.
Bei der Definition der Tabellen sollte man beachten, dass man keine Eigenschaften definiert, die nie oder nur
ganz selten Werte beinhalten, da jede zusätzlich Spalte, die definiert aber nicht verwendet wird, in jedem Datensatz unnötig Speicherplatz verbraucht und die SQL-Statements vergrößert. Wenn auch die Auswirkungen einer
einzelnen Eigenschaft nicht ins Gewicht fallen, kann sich bei sehr vielen Eigenschaften schon ein relevanter
Wert ergeben.
Auto-Grow
Die dynamische Erweiterung von Datenbankdateien ist ein sehr angenehmes Feature, das den Administratoren
erspart, das Datenwachstum überwachen zu müssen. In einer Migration hat dieses Feature aber definitiv nichts
zu suchen, da jede nachträgliche Erweiterung einer Datenbankdatei einerseits zu einer Wartezeit führt und andererseits zur Fragmentierung der Datenbankdateien auf der Festplatte führen kann. Besser ist es jedenfalls, die
Datenbank schon in der endgültigen Größe zu definieren und auch den Platz für die Indizes schon ausreichend
zu dimensionieren.
Device-Placement
Genauso wissenschaftlich wie emotionell wird die Diskussion geführt, welches Disk-Layout oder welcher RAIDLevel für welche Dateien ideal oder zumutbar ist. Die Meinungen reichen hier von „1 RAID 10 aus mindestens
zwei dedizierten Festplatten für jede Datei“ bis zu „1 RAID 50 für alles“, und jeder bringt seine Argumente vor.
Von meiner Warte aus möchte ich nur auf die Wichtigkeit des Themas hinweisen, ich überlasse diese Diskussion aber gerne anderen (siehe z.B. [MoNo03]).
6 Optimierungen
6.5 Optimierungen am Datenbanksystem
6.6 Fabasoft Components MMC-Service-Optimierung
6.7 Von Objekten und Töpfen
6.6
Fabasoft Components MMC-Service-Optimierung
Die Fabasoft Components MMC-Services sind die Zugriffsschicht von Fabasoft Components auf das Dateisystem. Sie implementieren selbst nicht viel Funktionalität und daher hängt die Performance der Fabasoft Components MMC-Services vor allem von der Performance des darunter liegenden Dateisystems und des Storagesystems ab.
Die Anzahl der Worker Threads ist auch hier zu konfigurieren, wobei die Anzahl der verwendeten Threads meistens geringer ist, als die Zahl der importierenden Clients.
Um unter Microsoft Windows das NTFS performanter zu machen, sollten in der Registry unter
HKLM\SYSTEM\CurrentControlSet\Control\Filesystem folgende Werte eintragen werden:
°
°
°
NtfsDisable8dot3NameCreation=1
NtfsDisableLastAccessUpdate=1
NtfsMftZoneReservation=2, 3 oder 4 (Default=1)
Diese Änderungen wirken sich auf alle Volumes des Servers aus und der Server muss rebootet werden, damit
diese wirksam werden.
6.7
Von Objekten und Töpfen
Nachdem jetzt so viel von Optimierungen die Rede war, kommen wir zur eigentlichen Frage: Warum ist der
Datenimport so langsam?
Das erinnert mich an die Frage, warum die Töpfe im Geschirrspüler nicht sauber geworden sind. Antwort des
Herstellers: Es ist sicher nicht die Maschine schuld, nicht das Wasser und wohl auch nicht das Waschmittel,
sondern man hat das Geschirr falsch eingeräumt.
113
Beim Datenimport ist das genauso: Schuld ist weder Fabasoft Components/COLD, noch das Fabasoft Components COO-Service, noch der Rechner an sich – auch wenn es auf jeder Ebene noch ein wenig besser ginge –
sondern es ist die Konfiguration, die einen schnellen von einem langsamen Datenimport unterscheidet. Nur, wie
findet man heraus, was man an der Konfiguration zu ändern hat? Beim Geschirrspüler werden vom Hersteller in
der Bedienungsanleitung einige Regeln aufgestellt, wie zum Beispiel, dass man Töpfe nicht ineinander stellen
soll. Genauso gibt es hier eine Checkliste, über die man bereits vor dem Import einige „Problemzonen“ identifizieren kann. Wenn das noch nicht zu den gewünschten Ergebnissen führt, dann muss man während der Laufzeit
des Imports den Problemen auf den Grund gehen. Diese zwei Phasen nenne ich statische- bzw. dynamische Problemanalyse.
Statische Problemanalyse
Bei der statischen Problemanalyse geht es zuerst einmal darum, auf Basis des Objektmodells Probleme zu erkennen und zu adressieren. Dazu betrachtet man zuerst die Eigenschaften der Objektklassen, die man importiert.
Nummeratoren
Auf die Nummeratoren wurde bereits eingehend eingegangen. Um Nummerator-Eigenschaften muss man sich
jedenfalls kümmern, da nicht zuletzt die Datenkonsistenz davon abhängt.
Rückwärtsverkettungen
Rückwärtsverkettungen implementieren eine bidirektionale Verbindung zwischen zwei Objekten. Setzt man also
eine Referenz in der einen Richtung, wird automatisch die Referenz in die andere Richtung mitgeführt. Dafür
wird ein zusätzliches Objekt erzeugt, das auf der Seite der Rückwärtsverkettungseigenschaft die Liste der referenzierten Objekte verwaltet. Die Änderungen werden durch Aktionen des Fabasoft Components Kernels konsistent durchführt. Diese Funktionalität kann damit auch nicht deaktiviert werden. Das bedeutet, dass diese referenzierten Objekte implizit verändert werden. Bei der Änderung der Rückwärtsverkettungseigenschaften werden
jedenfalls die Rückwärtsverkettungsobjekte gesperrt, was einen erheblichen negativen Einfluss auf die Performance hat.
6 Optimierungen
6.7 Von Objekten und Töpfen
Methoden von Eigenschaften
Die dritte Klasse von Eigenschaften, die bei der statischen Problemanalyse betrachtet werden, sind jene Eigenschaften, die eine Konstruktoraktion oder eine Aktion vor dem Speichern der Eigenschaft eingetragen
haben. Darunter fallen auch die normalen Nummerator-Eigenschaften. Konstruktoraktionen werden beim Erzeugen eines Objekts jedenfalls durchgeführt, Aktionen vor dem Speichern der Eigenschaften nur, wenn der Eigenschaft in der aktuellen Transaktion ein Wert zugewiesen wurde. Das kann aber auch durch einen Initialisierungswert, den Konstruktor oder durch andere Methoden geschehen und ist damit auch nicht auf Eigenschaften
beschränkt, die im Datenimport verwendet werden.
Ein Beispiel für eine Eigenschaft mit Konstruktoraktion ist die Eigenschaft Workflow ([email protected]:
workflow), die auf Ebene der Objektklasse Objekt also für jedes Objekt definiert ist und die aus der Konfiguration ausliest, ob ein Workflow initialisiert werden soll und diesen auch gleich anlegt. Auch wenn kein Workflow erzeugt wird, so wird doch die Methode aufgerufen und die Konfiguration nach diesbezüglichen Einträgen
durchsucht.
Bei diesen Eigenschaften sollte untersucht werden, ob der Konstruktor oder die Aktion vor dem Speichern
der Eigenschaft beim Import überhaupt ausgeführt werden müssen bzw. ob man deren Funktion durch Mittel
des Datenimports ersetzen kann. Der Entwickler kann auch bereits bei der Implementierung vorsehen, dass eine
Aktion im Fall des Datenimports nicht oder nur teilweise ausgeführt werden muss, indem er die Transaktionsvariable TV_BATCHMODE oder TV_LOADMODE der Softwarekomponente [email protected] prüft und,
wenn diese gesetzt ist, beispielsweise Konsistenzprüfungen übergeht oder andere Eigenschaften nicht ändert,
die vom Datenimport selbst gesetzt werden.
Methoden von Objekten
Folgende Methoden werden im Lauf des Erzeugens und Speicherns jedes Objekts aufgerufen:
°
°
Die Objektkonstruktoren ([email protected]:ObjectConstructor)
Die Aktionen vor dem Schreiben der Objekte ([email protected]:ObjectPrepareCommit)
115
°
Die Aktionen nach dem Schreiben der Objekte ([email protected]:ObjectCommitted)
Während die erste auf alle geänderten Objekte aufgerufen wird, bevor noch die Set-Aktionen der einzelnen
Eigenschaften aufgerufen werden, wird die zweite aufgerufen, nachdem das Commit erfolgreich abgeschlossen
wurde. Viele Lösungen stecken viel Anwendungsfunktionalität in diese Aktionen hinein, um Konsistenzprüfungen durchzuführen, Werte zu berechnen oder weiterführende Änderungen durchzuführen. Im Fall des Datenimports sind nicht alle dieser Aktionen unbedingt notwendig und können entweder gänzlich vernachlässigt oder
durch entsprechende Konfiguration ersetzt werden.
Analyse
Bei einer statischen Analyse betrachtet man vor allem die bei den Eigenschaften eingetragenen Methoden zum
Erzeugen, Lesen und Setzen der Werte. Bei all diesen Aktionen und deren Wrappern wird überprüft, ob diese
beim Datenimport ausgeführt werden müssen. Gegebenenfalls können sie durch Setzen von entsprechenden
Optionen übergangen und im Bedarfsfall deren Funktionalität durch weitere Zuordnungen ersetzt werden.
Dynamische Problemanalyse
Im Gegensatz zur statischen Problemanalyse, die auf Basis des Objektmodells durchgeführt wird, bedient sich
die dynamische Problemanalyse diverser Werkzeuge, die zum Aufspüren der Problemursachen dienen. Alle diese Werkzeuge setzen voraus, dass ein problematischer Import gerade ausgeführt wird bzw. die Ausführung
begonnen werden kann.
Diese Werkzeuge sind
°
°
°
Unter Microsoft Windows der Performance-Monitor bzw. unter Linux die entsprechenden SNMP-Counter
Der Trace-Kernel zur Identifikation von Bottlenecks am Client
Datenbankanalyse-Tools
6 Optimierungen
6.7 Von Objekten und Töpfen
Performance Monitor/SNMP
Auf jeder Ebene, die vom Datenimport betroffen ist, gibt es eine Vielzahl von Performance-Countern, die Hinweise auf Bottlenecks liefern können.
Damit kann die Ebene des Problems meist rasch eingegrenzt werden. Auf der betreffenden Ebene können Werkzeuge zur detaillierten Analyse eingesetzt werden.
Prozessorzeit
Der häufigste Grund für eine schlechte Performance ist die Auslastung der CPU am Client, auf dem der Import
gestartet wurde, also auf dem der Fabasoft Components Kernel ausgeführt wird. Dabei ist zu beachten, dass auf
einem Multiprozessorsystem die Gesamtlast meistens nicht mehr als der Anteil einer CPU betragen kann. Aussagekräftiger ist daher die Prozessorzeit des coo- bzw. w3wp-Prozesses. Unter Microsoft Windows wird dieser in Prozent einer CPU angegeben und kann folglich mehr als 100 % erreichen, wobei das derzeit eher eine
Wunschvorstellung als Realität ist. Hat man also eine Last um die 100 %, dann bedeutet das, dass der Client
ein Bottleneck darstellt, da zu viel am Client berechnet werden muss. Als Konsequenz muss man zum Beispiel
anhand eines Kernel-Traces versuchen, die Aktionen zu identifizieren, die diese Last verursachen und diese entweder zu ersetzen oder zumindest so umzuschreiben, dass weniger CPU-Zeit für deren Verarbeitungen benötigt
wird.
Ist die Last am Fabasoft Components COO- oder MMC-Service sehr hoch, so kann man dagegen strukturell
etwas unternehmen, indem man die Last auf mehrere Services verteilt. Eine Verringerung des Cache führt oft zu
einer Verringerung des CPU-Verbrauchs des Service, jedoch oft auf Kosten der Gesamtperformance. Wird am
Server, auf dem die Fabasoft Components MMC-Services betrieben werden, außer von den Fabasoft Components Services nennenswert Zeit benötigt, ist das möglicherweise auf einen Virenscanner zurückzuführen, der
jedenfalls zur Migrationszeit deaktiviert werden sollte.
Eine hohe Auslastung der CPU auf der Datenbank weist auf ineffiziente Abfragen hin, bei denen viele Datensätze durchsucht werden müssen, um ein Ergebnis zu berechnen. Wird also für eine Query ein Tablescan
gemacht und diese Tabelle ist vollständig im Speicher enthalten, so wird diese Operation mit großem CPU-Auf-
117
wand durchgeführt. Das hat neben dem CPU-Aufwand auch noch zur Folge, dass der Datenbank-Cache permanent von dieser Tabelle belegt wird und nicht für andere Aufgaben zur Verfügung steht. Dieses Verhalten kann
sich stark ändern, wenn entweder durch neu berechnete Statistiken die Zugriffspfade optimiert werden und
daher der Aufwand für die Bearbeitung sinkt, oder aber durch das Datenwachstum die Daten nicht mehr vollständig im Cache gehalten werden können und dadurch das CPU-Problem auf Kosten eines Disk-Problems
scheinbar behoben wird.
Oft kann man bei der Beobachtung der CPU-Auslastung die Phasen einer Transaktion beobachten, wie die Verarbeitung am Client beginnt, eventuell Suchen auf der Datenbank durchgeführt werden, dann die Aktionen am
Client durchgeführt werden und schließlich die Änderungen über das Fabasoft Components COO-Service bis zur
Datenbank kommen. Auch aufgrund der Länge dieser Phasen kann man bestimmen, welche Komponente das
Bottleneck ist. Um das besser beobachten zu können, ist es hilfreich, die Transaktionsgröße zu verändern, um zu
Transaktionszeiten von ca. 10-20 Sekunden zu kommen.
Festplatte
Alle Daten kommen irgendwo von einer Festplatte und landen schlussendlich auf einer. Damit ist auch die
Geschwindigkeit des Disksystems mitentscheidend für die Performance des Datenimports. Neben den Festplatten der Quell- und Zielsysteme wird auch die des Ladeclients beim Laden von Inhalten beansprucht. Ein entscheidender Faktor ist aber zumeist die Festplatte am Fabasoft Components MMC-Service und auf der Datenbank.
Folgende Performancecounter sind unter Microsoft Windows verfügbar und für die Analyse interessant:
°
°
°
°
°
°
% Disk Time
Disk Queue Length
Disk Read Bytes/s
Disk Write Bytes/s
Avg. Disk sec/Read
Avg. Disk sec/Write
6 Optimierungen
6.7 Von Objekten und Töpfen
Die Performance der Datenquelle ist erfahrungsgemäß von geringer Bedeutung, kann aber gerade bei der Verwendung von mehreren Ladeclients auch eine Rolle spielen. Bottlenecks auf Seite der Datenquelle können meistens durch die Konfiguration mehrerer Datenquellen entschärft werden, um die Quelldaten performant liefern
zu können. Die lokale Festplatte des Ladeclients als Datenquelle zu verwenden, ist beim Laden von Inhalten keine gute Variante, sofern auch das DOCDIR-Verzeichnis auf dieser Platte liegt, da die Daten lokal auf die Festplatte kopiert werden, was im Allgemeinen langsam ist.
Am Client ist die Festplatte im Fall vom Import von Inhalten ein limitierender Faktor. Alle Inhalte werden hier
zuerst von der Quelle gelesen und in das DOCDIR-Verzeichnis kopiert, bevor sie beim Commit auf das Backen
übertragen werden. Daher sollte man darauf achten, dass hier eine schnelle Festplatte verwendet wird und diese ausschließlich für das DOCDIR-Verzeichnis verwendet wird. Bei Importen ohne Inhalte wird die lokale Festplatte nicht wesentlich belastet.
Beim Schreiben von Inhalten am Fabasoft Components MMC-Service wird nach dem Schreiben einer Datei ein
Flush auf das Disksystem ausgeführt, um die neue Datei auf dem Medium zu sichern. Das bedeutet aber, dass
dieser Zugriff synchron durchgeführt wird und effektiv auf die Festplatte gewartet wird. Dieser Schritt kann von
einem SAN-System oder einem RAID-Controller mit Write-Buffer stark profitieren, da das Flush nicht auf die
Disk warten muss. Hier spielt auch die Auswahl des RAID-Levels eine Bedeutung. Wie groß der Unterschied zwischen den einzelnen Konfigurationen konkret ist, hängt aber stark vom verwendeten Disk-Subsystem und dessen Cache ab.
Besonders kritisch ist die Geschwindigkeit des Festplattensystems der Datenbank. Allerdings ist hier nicht
jeder Disk-Zugriff schlecht oder bremst den Datenimport. Schließlich müssen die Daten der Datenbank ja irgendwie geschrieben werden. Die Daten der Tabellen werden asynchron zur Verarbeitung auf die Platten geschrieben und werden bis dorthin lediglich im Datenbank-Cache geändert. Die Konsistenz wird dabei über die Datenbank-Logdateien garantiert, die – und das ist ein kritischer Pfad – beim Commit synchron auf die Platte geschrieben werden müssen. Im Unterschied zu den Daten, die meist ein zufälliges Zugriffsmuster aufweisen, werden
die Logs sequenziell geschrieben. Dem kann Rechnung getragen werden, indem die Logs auf dedizierten Festplatten platziert werden, die beim sequenziellen Schreiben kaum Bewegungen des Schreib- und Lesekopfes
benötigen. Die Daten hingegen werden auf möglichst viele Platten verteilt, damit die zufälligen Zugriffe auf
119
möglichst vielen Einheiten parallel servisiert werden können. Mit Buffered-Write (auch Write-Back-Buffering
genannt) kann man das Problem der Logs entschärfen, wenn das Storagesystem garantiert, dass selbst bei
einem Absturz oder Stromausfall keine Änderungen verloren gehen. Die Verwendung von möglichst vielen Platten für die Datenbereiche ist auch heute noch Voraussetzung für den effizienten Betrieb einer Datenbank.
Üblicherweise arbeitet ein Datenbanksystem anfangs, wenn der Datenbestand klein ist, optimal. In dieser Phase werden fast ausschließlich Schreiboperationen durchgeführt. Erst wenn die verwendete Datenbankgröße die
Dimension des Buffer-Cache erreicht hat, kann es zu einem Einbruch der Performance kommen. Das erkennt man
daran, dass auf einmal auch der Wert für „Disk Read Bytes/sec“ erhebliche Werte aufweist. Spätestens dann
zeigt sich, ob die Indizes greifen und damit nicht wegen Tablescans ganze Tabellen im Speicher gehalten werden müssen. Reads wirken sich immer direkt auf die Performance aus, da diese in der Regel synchron zur Verarbeitung durchgeführt werden müssen, wenn also die Anwendung auf das Ergebnis einer Query wartet. Gelesen wird aber nur, was sich nicht gerade im Buffer-Cache befindet, sodass durch eine Vergrößerung des BufferCache die Wahrscheinlichkeit steigt, dass diese Daten im Cache gehalten werden können. Wie bei den Clientund Service-Caches schon angesprochen, ist eine effiziente Ausnützung der Caching-Mechanismen durch die
Anwendung hilfreich. Damit kann die Menge der Daten, die in einer Phase benötigt wird, klein gehalten werden
und die Wahrscheinlichkeit steigt, dass diese Daten bereits im Cache vorhanden sind. Diese Optimierung steht
aber oft im Widerspruch zur Parallelisierung, die meistens darauf aufbaut, dass parallel mehrere verschiedene
Datenbereiche verändert werden und so das Workingset vervielfacht wird. Wenn also das Bottleneck auf der
Datenbank zu finden ist, kann potenziell eine spürbare Beschleunigung der Verarbeitung durch eine Reduktion
der Parallelität erreicht werden.
Der Wert von „Disk Write Bytes/sec“ ist bei den Logbereichen meistens relativ kontinuierlich, da hier bei jedem
Commit Daten anfallen. Bei den Datenbereichen werden Änderungen im Normalfall im Hintergrund geschrieben,
jedenfalls aber bei jedem Checkpoint (in Oracle z.B. beim Log-Switch). Ein Log-Switch ist eine synchrone Operation, die zu einer Wartezeit der Clients führt. Daher sollte die Anzahl der Checkpoints oder Log-Switches auch
gering gehalten werden, was in Oracle beispielsweise eine entsprechende Dimensionierung der Logdateien voraussetzt. Erkennt man also aus den Countern, dass regelmäßig hohe Spitzen in der Schreiblast der Datenbereiche auftreten, in Verbindung mit Pausen in der sonstigen Verarbeitung, sollte man sich um die Checkpoints küm-
6 Optimierungen
6.7 Von Objekten und Töpfen
mern. Die andere problematische Situation, dass Daten vorzeitig geschrieben werden müssen, entsteht wenn
der Buffer-Cache zu klein ist und damit geänderte Blöcke vermehrt auf die Festplatten geschrieben werden müssen, um Platz für andere Datenblöcke freizumachen. Um diese Schreibprozesse vom Normalbetrieb unterscheiden zu können, benötigt man aber die Counter der Datenbanken, denn eine kontinuierliche Schreiblast auf den
Datenbereichen ist durchaus normal und beeinträchtigt nicht die Performance, da sie asynchron zur eigentlichen
Verarbeitung erfolgt.
Die Werte von „Avg. Disk sec/Read“ und „Avg. Disk sec/Write” geben an, wie lange das Lesen bzw. Schreiben
eines Datenblockes auf die Disk benötigt. Diese sollten speziell bei den Platten mit Datenbank-Logs im Bereich
von maximal drei bis vier Millisekunden bleiben. Diese Zeit benötigt jede Transaktion mindestens auf der Datenbankseite für das Commit, denn jedes Datenbanksystem baut auf die Konsistenz des Datenbank-Logs auf und
damit müssen die Daten der Transaktion und die Entscheidung, ob ein Commit oder Rollback durchgeführt wurde, auf dem Log persistiert sein, bevor das Commit beendet wird. Die Situation kann einerseits durch das
Storagesystem beeinflusst werden, anderseits durch die Verwendung von größeren Transaktionen verbessert
werden, da damit die Anzahl der Commits reduziert wird.
Die „Disk Queue Length“ ist ein Maß für die Parallelität der Datentransferoperationen. Ist dieser Wert hoch,
übersteigt er also deutlich die Anzahl der physischen Platten, steigt damit die Wartezeit der Prozesse auf die
Daten an. Datenbanksysteme sind darauf ausgelegt, dass viele Vorgänge parallel bearbeitet werden, und daher
profitieren diese direkt von einer höheren Parallelität am Speichersystem.
Counter des Fabasoft Components Kernels
Es gibt neben der bereits besprochenen CPU einige interessante Counter, mit denen die Aktivitäten des
Fabasoft Components Kernels analysiert werden. Der Cache ist die zentrale Ressource des Fabasoft Components Kernels, wobei gerade hier nicht bei allen Imports eine hohe Hitrate erreicht werden kann. Die betreffenden Counter sind:
°
°
% Cache-Hit Rate
% Cache Used
121
°
°
°
°
°
Cached Objects
Objects Completely Loaded (Bulk)/sec
Objects Completely Loaded (Single)/sec
Objects Partially Loaded (Bulk)/sec
Objects Partially Loaded (Single)/sec
Mit diesen Performanceindikatoren kann die Aktivität des Cache gut nachvollzogen werden. Ob der Cache effizient funktioniert, hängt vom Workingset des Imports ab. Werden sehr viele Objekte linear abgearbeitet, kann
nur wenig Information aus dem Cache wiederverwendet werden und die Cache-Hit-Rate wird relativ niedrig werden (unter 80 %). Werden viele Operationen auf einem begrenzten Datenbestand durchgeführt, wird die Rate
steigen.
Ziel des Cache ist, die Werte der Counter „Object Completely/Partially Loaded (Bulk/Single)/sec“ durch die Zwischenspeicherung der Objekte niedrig zu halten. Diese geben die Anzahl der RPCs an, die zum Laden von Daten
an das Fabasoft Components COO-Service abgesetzt werden. Vom Import werden dabei die in Zuordnungen verwendeten Eigenschaften aller beteiligten Objekte in Bulk-Operationen von den Services geladen. Werden jedoch
in Aktionen Eigenschaften verwendet, die nicht direkt aus der Definition des Datenimports ersichtlich sind, so
werden die darin referenzierten Objekte meist einzeln geladen und das führt zu einer großen Anzahl von einzelnen RPCs, die man dann unter „Objects Completely/Partially Loaded (Single)/sec“ beobachten kann. Eine Optimierung sollte daher diese RPCs verhindern, indem diese Aktionen unterbunden werden oder durch zusätzliche
Zuordnungen ersetzt werden. Werden von einer Objektklasse zusätzlich zu den Eigenschaften, für die Zuordnungen definiert sind, auch noch andere Eigenschaften benötigt, so können diese beim Laden der Eigenschaften der
Objekte gleich mitgenommen werden, indem eine Zuordnung zu dieser Eigenschaft definiert wird und der
Änderungsmodus auf „Ignorieren“ gestellt wird. Um welche Eigenschaften es sich handelt, kann man aus dem
Kernel-Trace ablesen. Nicht lösen lassen sich damit Objektbeziehungen, die nicht im Datenimport definiert sind,
sondern die erst von der Methode verwendet werden.
6 Optimierungen
6.7 Von Objekten und Töpfen
Die Objektsperren spiegeln sich in den Countern
°
°
Objects Locked/sec
Objects Unlocked/sec
wieder. Wie schon öfters erwähnt, sind Objektsperren generell langsam und für die Funktion eines Imports nicht
notwendig, vorausgesetzt die Daten werden nicht gleichzeitig von anderen Stellen aus geändert. Daher ist auch
als Defaultwert beim Datenimport eingestellt, dass die Objekte nicht gesperrt werden. Ist diese Voraussetzung
nicht erfüllt, weil der Import beispielsweise im laufenden Betrieb durchgeführt wird, so sollte die Objektsperre
aktiviert werden. Damit werden nur jene Objekte modifiziert, bei denen die Sperre erfolgreich war. Neu erzeugte Objekte brauchen und können nicht gesperrt werden, da sie von keiner anderen Stelle aus geändert werden
können, bis sie das erste Mal committet wurden. Implizite Sperren, wie zum Beispiel die der Rückwärtsverkettungsobjekte, können durch Mittel des Datenimports nicht verhindert werden. In diesem Fall muss in der Implementierung der Methoden berücksichtigt werden, dass im Fall eines Imports keine Sperre erfolgen sollen
(TV_BATCHMODE).
Der Wert des Counters „Queries/sec“ gibt die Anzahl der Suchabfragen wieder, die vom Fabasoft Components
Kernel gemacht werden. Dieser Counter beinhaltet Suchen, die vom Datenimport selbst gemacht werden und
zur Identifikation von Objekten notwendig sind, aber möglicherweise auch solche, die implizit von Methoden aus
durchgeführt werden und zu einer Verzögerung des Datenimports führen können. Der Kernel-Trace hilft in diesem Fall den Kontext der Query herauszufinden.
Die Versionierung von Objekten ist in den meisten Fällen unerwünscht, wird aber vielfach automatisch ausgelöst, wenn etwa der Bearbeiter wechselt. Diese automatische Versionierung, die in der Aktion vor dem
Schreiben der Objekte ([email protected]:ObjectPrepareCommit) durchgeführt wird, bremst
den Datenimport erheblich. Die Versionierung erkennt man am Counter „Versions Created/sec“, der bei vorliegender Versionierung einen Wert ungleich 0 liefert. Um die Versionierung zu verhindern, kann man die Aktion
vor dem Schreiben der Objekte übergehen oder die Versionierung für die betroffene Objektklasse gänzlich
deaktivieren.
123
Counter der Fabasoft Components Services
Für alle Services gleich sind die Counter des Performanceobjekts COO-RPCs, die Informationen zu den RPC-Verbindungen und zu den Worker Threads der Services beinhalten. Während der Datendurchsatz, enthalten in den
Countern
°
°
°
Bytes Received/sec
Bytes Sent/sec
Bytes Total/sec
ein Maß für die Netzwerkbelastung durch das Service ist, aber meistens nur einen Bruchteil der zur Verfügung
stehenden Kapazität nutzt, ist der Wert von
°
Allocated Threads
von entscheidender Bedeutung. Wie im Abschnitt über die Serviceoptimierung bereits ausgeführt, führt eine
zu geringe Anzahl von Worker Threads zu Wartezeiten und verlängert so die Ladezeit. Ist also die Anzahl
der Allocated Threads über eine längere Zeit gleich der konfigurierten Anzahl der Worker Threads, sollte man
diese Anzahl erhöhen. Das kann man direkt in der Registry unter HKEY_LOCAL_MACHINE\
SOFTWARE\Fabasoft\Fabasoft Components Server\Domain n.m\Service x im
Wert Worker Threads tun oder aber in der Fabasoft Components Domäne am Serviceobjekt umstellen und
Syncronize Registry Entries aufrufen. Jedenfalls muss das Service danach neu gestartet werden, um die
Änderung zu übernehmen.
Interessant am Fabasoft Components COO-Service sind die Cache-Counter
°
°
°
°
°
% Cache Hit Rate
% Cache Used
Cached Objects
Cache max MB
Objects Loaded/sec
6 Optimierungen
6.7 Von Objekten und Töpfen
6.8 Der Kernel-Trace
wobei die Counter von Version 6 auf Version 7 durch die Umstellung des Cachelayouts geändert wurden. In
jedem Fall gibt die „% Cache Hit Rate“ einen Wert für die effiziente Nutzung des Cache an, wobei es aber sehr
von der Struktur des Datenimports und damit des verwendeten Workingsets abhängt, ob der Cache überhaupt
effizient nutzbar sein kann. Davon hängt es auch ab, ob eine Vergrößerung des Cache die Trefferquote erhöhen
kann oder nur den Speicher mehr auslastet. Eine niedrige „% Cache Hit Rate“ und damit ein konstant hoher Wert
von „Objects Loaded/sec“ weist jedenfalls auf ein Bottleneck hin.
6.8
Der Kernel-Trace
Der Kernel-Trace ist eine schier unerschöpfliche Quelle der Information, allerdings oft nur für „Wissende“. An
dieser Stelle sollen nur ein paar grundlegende Informationen erörtert werden, die man einfach aus dem Trace
extrahieren kann und die für eine erfolgreiche Optimierung von Datenimporten notwendig sind.
Erstellen der Traces
Es gibt zwei Arten von Trace-Kernels: Der eine wird im jeweiligen plattformspezifischen Unterverzeichnis von
„Setup/ComponentsBase/Trace“ der Installations-CD mit dem Produkt mitgeliefert und generiert die ausführliche Version der Traces. Der Umfang der ausgegebenen Traceausgaben wirkt jedenfalls abschreckend und bietet dem neugierigen Einsteiger zuerst einen derartigen Überfluss an Unverständlichkeiten, dass der Trace im
besten Fall beim Fabasoft Support landet. Mit diesem Überfluss an Information ist auch ein erheblicher Aufwand
bei der Generierung verbunden, sodass der eigentliche Datenimport sehr langsam wird. Allein um bis zum
Datenimport zu kommen, vergeht bereits beträchtlich viel Zeit, speziell wenn man den Datenimport vom Webserver aus durchführt. Alternativ dazu gibt es für manche Versionen einen so genannten „EEE“-Trace-Kernel, der
vom Support zur Verfügung gestellt werden kann, und der wesentlich weniger Informationen beinhaltet, als der
vollständige Trace-Kernel.
125
Interpretation des Traces
Das grundlegende Problem bei der Optimierung von Datenimporten ist die Frage:
In welchen Methoden wird viel Zeit verbraucht?
Genau das kann aber mit dem Kernel-Trace einfach herausgefunden werden, indem man aus dem Trace jene Zeilen herausfiltert, die den Start und das Ende eines Methodenaufrufs markieren. Vorausgesetzt man hat mit nur
einem Thread einige wenige Datensätze importiert, sind vielfach die Schuldigen schnell gefunden.
Der Header jeder Zeile des Traces enthält folgende Informationen:
05688: 7.027: KS|0x974|0x9F8|coo: <Info>
1. eine fortlaufende Zeilennummer
2. eine Zeitinformation relativ zum Startzeitpunkt des Traces
3. KS bedeutet, dass es sich um einen Kernel-Tracepunkt handelt
4. 0x974 ist die Prozess-ID
5. 0x9F8 ist die Thread-ID
6. und coo ist der Name der Anwendung
7. danach folgt die eigentliche Information
Filtert man also den Trace nach „MethodImp::Call“, so erhält man eine Liste mit den Start- und Endpunkten der
Methodenaufrufe. Die Zeile mit [email protected]:ImportDataSelectedObjects oder
[email protected]:ImportRemote markiert dabei den Beginn des Imports. Danach wird ein Thread
gestartet, der den eigentlichen Import vornimmt. In diesem Thread wird das Datenimportobjekt gesperrt, damit
man einen Import nicht gleichzeitig durchführen kann, eventuell wird die Initialisierung der Suchbäume gemacht,
der Reader Thread gestartet und erst danach werden die Worker Threads erzeugt.
6 Optimierungen
6.8 Der Kernel-Trace
Verarbeitung eines Datenblocks
In den Verarbeitungs-Threads werden die Datenblöcke, die von dem Reader Thread zusammengestellt werden,
in folgender Weise verarbeitet:
Phase 1: Suchen und Anlegen von Objekten
Für jede Objektklasse werden entsprechend der Konfiguration die Objektinstanzen gesucht und angelegt. Dafür
werden folgende Schritte durchgeführt:
°
°
°
°
°
Objekte im lokalen Suchbaum suchen
Objekte über die Objektsuche suchen
Laden der Eigenschaften der Objekte
Objekte erzeugen ([email protected]:ObjectCreate)
°
Eigenschaftskonstruktoren (Die entsprechenden Eigenschaften finden sich im Trace neben dem Text
AttrSet)
°
Objektkonstruktor ([email protected]:ObjectContructor)
Objekte sperren ([email protected]:ObjectLock)
Phase 2: Setzen der Eigenschaften der Objekte
Es werden pro Datensatz die Zuordnungen ausgewertet und dabei die Eigenschaften gesetzt.
°
Aufruf des Filterskripts für Objekte (vor dem Commit)
Commit der Transaktion
°
°
Aufruf der Aktion vor dem Schreiben der Objekte
Aufruf der Aktion zum Setzen der Eigenschaften
127
°
°
Commit auf der Datenbank
Aufruf der Aktion nach dem Schreiben der Objekte
Nachbearbeitung
Zuletzt wird noch das Filterskript für Objekte nach dem Commit aufgerufen
Interpretation
Meistens ist es nicht wichtig, einen Kernel-Trace in seiner Gesamtheit zu verstehen. Im ersten Ansatz hilft es,
anhand der aufgerufenen Methoden diejenige Stelle zu identifizieren, an der die meiste Zeit verbraucht wird und
die dort verwendeten Funktionalitäten auf ihre Notwendigkeit hin zu untersuchen und Maßnahmen zu ergreifen,
um diese zu entschärfen.
6 Optimierungen
6.8 Der Kernel-Trace
129
7
Konfiguration
7 der Datenquellen
Nach dieser doch eher tiefer gehenden Betrachtung der Analyse- und Optimierungsmöglichkeiten
widmet sich dieses Kapitel einem Thema, das viel direkter mit dem Datenimport zu tun hat: den konkret zur Verfügung stehenden Datenquellen und deren Konfiguration.
Jeder Datenimport verarbeitet die Daten, die von einer bestimmten Datenquelle, die im Datenimportobjekt definiert ist, geliefert werden. Folgende Datenquellen stehen zur Verfügung:
1. ODBC (Open Database Connectivity): Sowohl auf der Microsoft Windows-Plattform als auch unter Linux
steht mit ODBC eine allgemeine Programmschnittstelle für Datenbanken zur Verfügung, für die es auf beiden Plattformen eine Vielzahl von Treiberimplementierungen für verschiedene Datenbanken und Datenformate gibt.
2. Ausschließlich unter Microsoft Windows ist alternativ zu ODBC die Programmschnittstelle OLE DB (Object
Linking and Embedding Database) für die Anbindung von Datenbanken definiert. Auch über diese Schnittstelle kann ein Datenimport seine Quelldaten bekommen. Von Fabasoft wird im Rahmen der Softwarekomponente [email protected] ein eigener Fileprovider auf Basis des OLE DB-Protokolls mitgeliefert, über
den Inhalte des Dateisystems geladen werden können.
3. Speziell um aus Druckdateien Daten extrahieren zu können wurde der Report-Umsetzer implementiert,
über den auf Basis von Beschreibungen, wo sich auf einem Formular die relevanten Informationen befinden,
die Quelldaten für den Import extrahiert werden können.
4. Ganz spezielle Datenquellen lassen sich über Datenquellen-Skripts definieren, durch die (derzeit nur auf
der Microsoft Windows-Plattform mit VBScript) auf beliebige Daten zugegriffen werden kann oder Daten
algorithmisch generiert werden können.
Mit Fabasoft Components Version 7 kommen einige andere Datenquellen hinzu:
°
LDAP (Lightweight Directory Access Protocol) ist ein standardisiertes Protokoll für den Zugriff auf Directories, wie zum Beispiel das Microsoft Active Directory oder OpenLDAP, die unter anderem für die Verwaltung
von Benutzerdaten und Gruppen verwendet werden. Mit der Anbindung von LDAP-Verzeichnissen ist eine
131
automatisierte Übernahme und Aktualisierung von Log-in-Informationen aus dem Directory in die Benutzerverwaltung der Fabasoft Components Domäne möglich.
°
Seit kurzem stehen auch jene Datenbankanbindungen direkt für den Datenimport zur Verfügung, die von den
Fabasoft Components Services verwendet werden. Über diese ADE DB genannte Schnittstelle sind vor
allem die Datenbanksysteme Oracle (über die OCI-Schnittstelle) und PostgreSQL über deren datenbankspezifisches Interface angebunden und können damit auch ohne Installation von ODBC-Treibern verwendet werden.
°
CSV-Dateien (Comma-Separated Values) sind sehr gut zum Transport von Tabellen in Textform geeignet.
Zwar gibt es auf Microsoft Windows und Linux ODBC-Treiber, mit denen diese gelesen werden können,
jedoch müssen diese am jeweiligen System extra konfiguriert werden. Daher wurde eine CSV-Datenquelle
implementiert, mit deren Hilfe man auf jeder Plattform gleich in einfacher Weise CSV-Dateien importieren
kann.
Für die Definition der Datenquelle gibt es im Fabasoft Win32-Client der Version 6 einen Wizard. Diesen startet
man durch Auswahl des Menübefehls Datenquelle definieren aus dem Kontextmenü des Datenimportobjekts.
Zuerst wählt man aus den möglichen Typen der Datenquelle die gewünschte aus.
Danach kommt man je nach Datenquelle zu unterschiedlichen Dialogen, wie sie in Abbildung 17 für ODBC und
OLE DB dargestellt sind.
7. Konfiguration der Datenquellen
133
Abbildung 17
Auswahl einer ODBC- bzw.
OLE DB Datenquelle
Bei ODBC kommt man auf den Auswahldialog für ODBC-Datenquellen, der von Microsoft Windows zur Verfügung gestellt wird und über den eine File- bzw. Machine Data Source erstellt und ausgewählt werden kann. FileDatenquellen werden durch eine Datei definiert, deren Name zur Definition der Datenquelle verwendet wird.
Eine Machine Data Source ist in der Microsoft Windows-Registry definiert und kann daher nicht so einfach im
Rahmen der Migration verteilt werden.
Bei OLE DB wird stattdessen der Auswahldialog für die UDL-Datei angezeigt. In einer UDL-Datei werden die Verbindungsparameter zur OLE DB-Datenquelle als Text abgelegt. Als Verbindungsinformation können entweder der
Dateipfad zur UDL-Datei oder aber die Parameter aus der Datei selbst verwendet werden.
Der nächste Schritt ist in jedem Fall die Auswahl der zu importierenden Tabelle. Angeboten werden alle Tabellen und Views im aktuellen Schema (siehe Abbildung 18).
Abbildung 18
Auswahl der Tabelle
und der Spalten
In unserem Beispiel wird die Tabelle Customers der Northwind-Datenbank gewählt und nach der Bestätigung mit OK kommt die Auswahl der Spalten:
Hier können die zu verwendenden Spalten ausgewählt werden, sodass nach der Bestätigung dieses Dialogs mit
OK das Datenimportobjekt mit den Verbindungsinformationen und einer Liste von Zuordnungen mit den gewählten Spalten gefüllt wird.
Im Fall der Auswahl der Skriptdatenquelle wird eine Liste der verfügbaren Skriptobjekte und Skript-Komponentenobjekte angezeigt. Nach der Auswahl des entsprechenden Skripts folgt auch hier die Auswahl der verfügbaren Spalten.
7. Konfiguration der Datenquellen
7.1 ODBC
7.1
oDBC
ODBC (Open Database Connectivity) ist sowohl auf der Microsoft Windows-Plattform als auch unter Linux verfügbar. Auf Basis dieser standardisierten Programmschnittstelle ist eine ganze Reihe von Treibern für die Anbindung verschiedenster Datenbanken verwendbar.
Während in Microsoft Windows ODBC standardmäßig mit dem Betriebssystem mitinstalliert wird, muss es unter
Linux explizit konfiguriert werden.
Einige der am häufigsten verwendeten Treiber und deren Konfiguration sind im Folgenden beschrieben.
Microsoft Excel
Microsoft Excel eignet sich sehr gut zur manuellen Erfassung von Listen, da die meisten Benutzer mit dem
Medium vertraut sind. Entwirft man entsprechende Vorlagen, können zum Beispiel Daten aus vielen Abteilungen zusammengetragen werden, die automatisiert weiterverarbeitbar sind. Ein Problem entsteht allerdings gerade durch die Tatsache, dass die Benutzer beim Eingeben der Daten viele Freiheiten nutzen und es im Nachhinein mit einem erheblichen Aufwand verbunden ist, die Daten wieder in ein Zielformat zu konsolidieren. Außerdem eignet sich das Medium nur für kleine Datenmengen und nicht für alle Datentypen.
Kritisch bei Microsoft Excel ist die Verwendung von Datumswerten, da Microsoft Excel diese intern als Fließkommawerte speichert und nur in der Darstellung umrechnet. In der Datenquelle erscheinen jedoch nicht die formatierten Werte, sondern die internen Daten. Diese müssen daher im Filterskript für Rohdaten erst auf
Datumswerte umgerechnet werden. Auch bei Zahlen mit Nachkommastellen unterscheiden sich die formatierten Werte in der Anzeige von Microsoft Excel von den Werten, die über OLE DB an den Datenimport geliefert
werden und oft noch weitere Kommastellen oder die für Fließkommawerte typischen periodischen Dreier oder
Neuner enthalten.
Um Daten von Microsoft Excel als Datenquelle über ODBC zur Verfügung zu haben, muss man in Microsoft Excel
jedenfalls eine Spaltenüberschrift für jede Datenspalte definieren, die als Spaltenname auch im Datenimportobjekt verwendbar ist. Als Datenbereich ist entweder eine ganze Seite verwendbar, die unter dem Namen des
135
Datenblattes mit einem „$“ am Ende als Tabellenname erreichbar ist, oder man definiert einen Namen für einen
ausgewählten Datenbereich, unter dem die Daten dann auch für den Datenimport verfügbar sind (siehe Abbildung 19).
Abbildung 19
Definition eines
Datenbereichs in
Microsoft Excel
Jedenfalls ist darauf zu achten, dass während des Datenimports die Datei nicht in Microsoft Excel geöffnet ist,
da die Datei sonst nicht vom Treiber geöffnet werden kann.
CSV und Tab-Separated Files
CSV-Dateien (Comma-Separated Values) oder Tab-Separated Files sind Text-Dateien, die pro Zeile einen
Datensatz enthalten und bei denen die einzelnen Spalten durch ein bestimmtes Trennzeichen voneinander
getrennt werden. Was auch immer das Trennzeichen ist, ein Beistrich, ein Strichpunkt oder ein Tabulator-Zei-
7. Konfiguration der Datenquellen
7.1 ODBC
chen, diese Dateien eignen sich gut für den Datentransport, wenn man einige grundlegende Konventionen für
die Daten vereinbart:
Trennzeichen
Meistens werden Beistriche, Strichpunkte oder Tabulatorzeichen als Spaltentrennzeichen verwendet und CRLF
als Zeilentrennzeichen. Strichpunkte und Tabulatorzeichen eignen sich besonders gut, da sie im Gegensatz zu
Punkten oder Beistrichen nicht als Dezimal- oder Datumstrennzeichen verwendet werden und daher (außer in
Zeichenketten) nicht vorkommen können.
Zeichenketten
Zeichenketten, die Sonderzeichen oder aber auch das Trennzeichen enthalten, werden oft unter Anführungszeichen gesetzt. Damit auch Anführungszeichen in diesen Texten enthalten sein können, werden diese im Text verdoppelt. Die Verwendung eines Escape-Characters (z.B. Backslash „\“) ist eher unüblich.
Zahlenformat
Es muss festgelegt werden, welches Zeichen als Komma und welches optional auch als Tausendertrennzeichen
verwendet wird. Ob eine sprachspezifische Version oder ein standardisiertes Format verwendet wird, liegt im
Ermessen der beteiligten Personen.
Format für Datum und Zeit
Hier gilt ähnliches wie bei den Zahlenformaten. Zusätzlich kann hier auch noch die Verwendung von Zeitzonen
eine Rolle spielen.
Zeichensatz
Umlaute und Sonderzeichen werden in verschiedenen Zeichensätzen unterschiedlich kodiert und daher ist es
wichtig, die Datei mit demselben Zeichensatz zu lesen wie sie geschrieben wurde. Wenn man vom Unicode-
137
Zeichensatz und dessen Repräsentationen UTF-8 und UTF-16 absieht, so kann man bei der Verarbeitung
meistens nicht automatisch auf den richtigen Zeichensatz schließen, sondern muss diesen explizit festlegen, um
vor Überraschungen sicher zu sein.
Spaltenbezeichnungen
Die Spaltennamen werden in CSV-Dateien in der Regel in der ersten Zeile der Datei spezifiziert. Dabei sollte
beachtet werden, dass diese keine Sonderzeichen enthalten sollten (speziell ein „@“-Zeichen am Beginn einer
Spaltenbezeichnung würde zu Problemen beim Datenimport führen). Auch sollten sich die Bezeichnungen von
Spalten nicht nur durch die Groß-/Kleinschreibung unterscheiden, da diese Unterscheidung nicht an allen Stellen berücksichtigt wird.
Datentypen
Die Spaltenbreiten werden oft von den Treibern aufgrund des Inhalts der ersten Datensätze analysiert. Besser
ist es jedoch definitiv festzulegen, welchen Datentyp eine Spalte hat und welche maximale Länge deren Inhalte haben kann. Für den Datenimport ist eine Erkennung des Datentyps nicht erforderlich, da die Werte beim
Import immer als Zeichenketten gespeichert und erst beim Setzen der Eigenschaften auf den Datentyp der Eigenschaft konvertiert werden.
Leerwerte am Zeilenende
Einige Datenquellen optimieren die CSV-Datei dahingehend, dass alle Spaltentrennzeichen weggelassen werden, denen bis zum Zeilenende keine Spalte mehr folgt, die einen Wert enthält. Diese Optimierung wird nicht
von allen Treibern unterstützt und sollte daher nur verwendet werden, wenn sie definitiv von allen beteiligten
Programmen richtig erkannt wird.
Der Microsoft Text-Treiber kann die üblichen CSV-Dateien lesen und kann über Konfigurationsdateien, die im
Verzeichnis der Quelldatei liegen müssen, relativ genau konfiguriert werden (siehe [MSDN04]).
7. Konfiguration der Datenquellen
7.1 ODBC
7.2 OLE DB
In Fabasoft Components Version 7 wurde als Alternative zum ODBC-Text-Treiber ein eigener Datenquellentyp
implementiert, der ohne Verwendung von ODBC einen Import von CSV-Dateien implementiert.
Oracle unter Linux
Während unter Microsoft Windows ODBC bereits bei der Installation des Betriebssystems mitinstalliert wird,
gibt es dafür unter Linux ein eigenes Projekt namens unixODBC (siehe [Gorh06]). Dort können auch die jeweiligen Versionen für die einzelnen Plattformen bezogen werden.
Der erste Schritt der Konfiguration von ODBC-Treibern unter Linux ist also die Installation des unixODBC-Pakets.
Der nächste Schritt ist die Installation des ODBC-Treibers für die jeweilige Datenbank. Für Oracle können diese
Pakete von der Webseite [Orac07] für die jeweilige Client-Version heruntergeladen werden.
Die weitere Konfiguration ist einerseits in der Installationsanleitung der Pakete, andererseits für Version 6.1 in
einem White-Paper im Fabasoft technet beschrieben.
7.2
OLE DB
Die von Microsoft in vielen Produkten unterstützte Datenbankschnittstelle OLE DB bietet einige Vorteile gegenüber der älteren ODBC-Technologie, wie sie auch unter Linux verfügbar ist, jedoch werden die meisten Features
von Fabasoft Components/COLD nicht benötigt. Trotzdem ist sie gegenüber ODBC zu bevorzugen, da es in der
Regel die aktuelleren Treiber für OLE DB gibt. Für die Rückwärtskompatibilität gibt es einen OLE DB-Treiber für
ODBC-Datenquellen, mit dem unter Verwendung der OLE DB-Schnittstellen auf ODBC-Datenquellen zugegriffen
werden kann, was aber in der Regel für Fabasoft Components/COLD-Datenimporte nicht besser ist, als gleich
direkt ODBC zu verwenden.
Die Verbindungsparameter zur OLE DB-Datenquelle können in der Datenquelle entweder gleich direkt angegeben werden, oder durch eine Datei mit der Endung „udl“. Erstellt man eine UDL-Datei, so kann man im Microsoft Datei-Explorer über den Kontextmenübefehl Properties die Verbindungsparameter interaktiv festlegen.
139
Definition der OLE DB-Datenquelle
Will man zum Beispiel eine Datenquelle zur Microsoft SQL Server Demo-Datenbank Northwind, die am lokalen SQL-Server liegt, definieren, so kann man wie folgt vorgehen:
1. In einem beliebigen Ordner eine Textdatei anlegen und dieser die Endung „.udl“ geben, z.B. „Northwind.udl“.
2. Den Kontextmenübefehl Properties auswählen (auf Deutsch Eigenschaften) (siehe Abbildung 20).
Abbildung 20
Definition einer
OLE DB-Datenquelle
3. Auf der Registerkarte „Provider“ den „OLE DB-Treiber für den Microsoft SQL Server“ auswählen.
4. Danach auf der Registerkarte „Connection“ den Namen des Servers eingeben oder auswählen, „Use
Windows NT Integrated security“ als Log-in-Information angeben und unter Punkt 3. die gewünschte Datenbank auswählen.
7. Konfiguration der Datenquellen
7.2 OLE DB
Abbildung 21
Konfiguration der
OLE DB-Quelldatenbank
5. Mit „Test Connection“ kann die Verbindung zur ausgewählten Datenbank geprüft werden.
6. Werden die Eingaben mit OK bestätigt, so werden die Parameter in der UDL-Datei als Textinformation abgespeichert. Diese Datei kann man zum Beispiel im Microsoft Editor öffnen und sieht dann folgende Information:
[oledb]
; Everything after this line is an OLE DB initstring
Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security
Info=False;Initial Catalog=Northwind;Data Source=FOMDEMO
Quelltext 2: UDL-Datei mit Parametern
141
Im Datenimport kann nun als Datenquelle entweder der Dateiname der UDL-Datei verwendet werden, oder man
kopiert aus dieser Datei die Zeile, die mit „Provider=…“ beginnt in die Datenquelleneigenschaft. Welche Variante man bevorzugt, hängt davon ab, ob man lieber die Datenquelle an einer Stelle im Dateisystem haben will und
in mehreren Datenimporten verwenden kann, oder ob man ohne externe Dateien auskommen will und daher die
Verbindungsinformation direkt ins Datenimportobjekt eintragen will.
Microsoft SQL Server
Microsoft SQL Server ist die am meisten verbreitete Datenbank auf der Microsoft Windows-Plattform. Mit der
„Microsoft SQL Server Desktop Engine“ (MSDE) 2000 bzw. der „SQL Server 2005 Express Edition“ stehen auch
freie Versionen der Datenbank zur Verfügung, die im Rahmen von Migrationen als Medium für Zwischendatenbanken eingesetzt werden können. Die Limitierungen – vor allem der Datenbankgröße auf zwei bzw. vier Gigabyte – müssen dabei jedoch beachtet werden.
Views, Cursors, Functions und Stored Procedures können die Vorbereitung der Rohdaten für den Import wesentlich erleichtern, indem schon vor dem Import Überprüfungen der Wertebereiche oder der Datenkonsistenz auf
den Quelldaten durchgeführt werden. Bei einigen Migrationen, bei denen Daten in anderen Formaten geliefert
wurden (z.B. in CSV-Dateien oder als Microsoft Excel-Arbeitsmappen) wurden die Daten zuerst mit DTS-Paketen
auf den SQL-Server übernommen, bevor die konsolidierten Daten dann importiert wurden. Damit konnten Konsistenzprüfungen durchgeführt und so einige Fehlerquellen ausgeschlossen werden.
Außerdem kann man über Cursors auf Basis der Rohdaten Nummeratoren nachbilden und so die aufwendige
Durchführung der Berechnung der Nummeratoren beim Ladevorgang ersetzen.
Microsoft Access
Ähnlich flexibel sind auch die Möglichkeiten von Microsoft Access, jedoch sollte man diese nur bei kleineren
Datenbeständen verwenden und wenn keine zu hohen Anforderungen an die Parallelität und Performance
gestellt werden. Als OLE DB-Treiber wird hier der „Microsoft Jet 4.0 OLE DB Provider“ verwendet und in der
Datenquelle der Name der MDB-Datenbankdatei angegeben.
7. Konfiguration der Datenquellen
7.2 OLE DB
File Provider
Der File Provider ist ein OLE DB-Provider, der auf der Microsoft Windows-Plattform mit der Softwarekomponente [email protected] mitgeliefert wird, und mit dem Verzeichnisbäume iteriert werden können. Er eignet sich besonders zur Übernahme von Datenbeständen in identisch strukturierte Ablagen in einer Fabasoft Components Domäne. Mit dem File Provider werden nicht die Inhalte an den Datenimport übergeben, sondern die
Datei- und Ordnernamen, also genau jene Informationen, die vom Datenimport benötigt werden, um die Inhaltseigenschaften von Objekten zu setzen bzw. die Hierarchien aufzubauen.
Das zu übernehmende Verzeichnis wird im Datenimportobjekt als Tabellenname eingetragen (z.B. „c:\“ oder
„d:\myfolder“). Darauf wird beim Importieren vom OLE DB-Provider eine Tabelle mit folgenden Spalten erzeugt:
SPALTE
BESCHREIBUNG
FolderName
Name des Verzeichnisses
FolderPath
Pfad des Verzeichnisses
ParentName
Name des übergeordneten Verzeichnisses von <Folder>
ParentPath
Pfad des übergeordneten Verzeichnisses von <Folder>
Tabelle 5: Spalten des File Providers
Weil meistens nicht für alle Dateien Objekte in der Fabasoft Components Domäne erstellt werden sollen, können die Dateierweiterungen der zu berücksichtigenden Dateitypen im Datenimportobjekt im Tabellennamen konfiguriert werden. Die Dateierweiterungen werden vor dem Tabellennamen in einer geschwungenen Klammer
getrennt durch Strichpunkte angegeben.
143
Gültige Angaben sind beispielsweise
°
°
°
{doc} c:\
{doc;xls;tif} c:\myfolder
c:\myfolder
Für jede der angegebenen Dateierweiterungen werden zusätzliche Spalten „<ext>Name“ und „<ext>Path“ angelegt, wobei „ext“ für die Dateierweiterung steht. Wenn nur ein Startverzeichnis angegeben wird und keine
Erweiterungen, dann wird als Default „{doc;xls;tif}“ angenommen.
Beispiel: Import aus Dateisystem
Die Angabe von „{doc} c:\“ als Tabelle im Datenimportobjekt erzeugt die Spalten FolderName,
FolderPath, ParentName, ParentPath, docName und docPath. Für die Datei
„c:\myfolder\temp\test.doc“ wird dann der folgende Datensatz erzeugt:
FolderName =
temp
FolderPath =
c:\myfolder\temp
ParentName =
myfolder
ParentPath =
c:\myfolder
docName = test
docPath = c:\myfolder\temp\test.doc
Nach der Angabe der Datenquelle müssen noch die Zuordnungstabelle und die Tabelle der Objektreferenzen im Datenimportobjekt so gesetzt werden, dass automatisch die Ordnerobjekte und (für das Beispiel) die
darin liegenden Word-Objekte erzeugt werden. Der Trick dabei ist, dass mit den Folder*-Spalten ein
Ordnerobjekt und mit den Parent*-Spalten ein weiteres Ordnerobjekt – unterscheidbar durch die Werte in der ID-Spalte in der Zuordnungstabelle – beschrieben wird.
7. Konfiguration der Datenquellen
7.2 OLE DB
In der Objektreferenzen-Tabelle wird dann das Ordnerobjekt, das durch die Folder-Spalten definiert wurde,
dem Ordnerobjekt, das durch die Parent-Spalten definiert wurde, in der Eigenschaft Objektliste
([email protected]:objchildren) zugeordnet. Weiters werden erzeugte Inhaltsobjekte (hier
Word-Objekte) dem Ordnerobjekt zugewiesen.
In dem in Abbildung 22 abgebildeten Datenimportobjekt ist der Datenimport für dieses Beispiel konfiguriert,
wobei folgende Punkte speziell zu beachten sind:
1. Damit beim mehrfachen Importieren derselben Dateien bereits früher erzeugte Objekte wiedergefunden
werden, wird der genaue (vollständige) Dateiname in der Eigenschaft Betreff ([email protected]:
objsubject) der Objekte gespeichert. Im Objektnamen wird nur der lesbarere Name ohne Pfad und
Dateierweiterung eingetragen.
2. Die Inhaltseigenschaft Inhalt ([email protected]:contcontent) in der zusammengesetzten
Eigenschaft Hauptinhalt ([email protected]:content) eines erzeugten Word-Objekts wird auf
den genauen Dateinamen docPath gesetzt. Fabasoft Components/COLD erkennt beim Importieren,
dass es sich um einen gültigen Dateinamen handelt und das Zielattribut eine Inhaltseigenschaft ist und
kopiert die Datei in das Inhaltsattribut des Objekts. Die Originaldatei wird nicht gelöscht. Gesetzte
Optionen sind „Muss im Aggregat definiert sein“, damit keine Hauptinhaltseigenschaft erzeugt wird,
wenn der Dateiname nicht gesetzt ist, und „Dateiname“, damit der Wert immer als Dateiname interpretiert wird, selbst wenn die Datei nicht mehr existieren würde. Anderenfalls würde der Wert der Spalte
über eine temporäre Datei als Inhalt dem Hauptinhalt zugewiesen, was in diesem Fall nicht sinnvoll ist.
3. Die Eigenschaft Endung der Datei ([email protected]:contextension) in der zusammengesetzten Eigenschaft Hauptinhalt ([email protected]:content) eines erzeugten Word-Objekts
wird auf den Festwert „doc“ gesetzt, damit beim Bearbeiten des Objekts automatisch die korrekte Applikation gestartet werden kann.
145
Abbildung 22
Konfiguration eines Imports
mit OLE DB File Provider
7. Konfiguration der Datenquellen
7.2 OLE DB
7.3 Report-Umsetzer
7.3
report-Umsetzer
Mit dem Report-Umsetzer steht in Fabasoft Components/COLD eine Datenquelle zur Verfügung, mit der Werte aus Textdateien gelesen werden können, wie sie beispielsweise beim Ausdruck von Formularen oder Reports
generiert werden.
Die Definition der Feldnamen und der Datenbereiche erfolgt in einem Report-Umsetzer-Objekt oder einem
Report-Umsetzerkomponentenobjekt. Wie bei den Datenimportobjekten unterscheiden sich die beiden
Objektklassen nur durch die Tatsache, dass Komponentenobjekte als Elemente von Softwarekomponenten leichter extrahiert und in anderen Fabasoft Components Domänen wieder eingespielt werden können. Dafür benötigen sie eine Referenz und die Zuordnung zu einer Softwarekomponente.
Abbildung 23
Konfiguration des ReportUmsetzers
147
Hier eine Beschreibung der einzelnen Eigenschaften:
EIGENSCHAFT
BESCHREIBUNG
Steuerzeichen
ignorieren
Wird die Eigenschaft auf „Ja“ gesetzt, so werden alle Steuerzeichen
(< ASCII(32)) unterdrückt.
OEM-zu-ANSIKonvertierung
Je nach Einstellung werden die gelesen Daten im ANSI- oder OEM-Zeichensatz
interpretiert
Kennung für
neue Seite
Zeichenkette, die die Dokumente innerhalb einer Druckdatei voneinander trennt
(Codes „{CR}“, „{LF}“, „{TAB}“ und „{FF}“ stehen für die Steuerzeichen „0xD“,
„0xA“, „0x9“ und „0xC“). Ein „^“-Zeichen bedeutet, dass die gesuchte Zeichenkette am Anfang einer Zeile stehen muss.
Kennung für
Zeilenende
Zeichenkette, die die einzelnen Zeilen des Dokuments trennt. Es sind hier dieselben Codes verwendbar, wie bei der Kennung für neue Seite.
Seitentrennung
gehört zu
Beim Import von Druckdateien trennt die unter Kennung für neue Seite eingestellte Kennung für neue Seite die einzelnen gedruckten Dokumente (Objekte).
Je nach Druckjob gehört die Zeile mit dem Trennstring nun entweder an den
Anfang eines neuen Dokuments, an das Ende des gerade gelesenen Dokuments
oder ist überhaupt nicht Teil des Dokuments. Diese Information kann für die
Bestimmung von Positionen innerhalb des Dokuments wichtig sein.
Folgende Optionen stehen zur Verfügung:
°
°
°
Nächster Seite: Die Trennzeile ist der Anfang eines neuen Dokuments
Vorheriger Seite: Die Trennzeile ist das Ende des gerade gelesenen Dokuments
Keiner Seite: Die Trennzeile ist nicht Teil eines Dokuments
7. Konfiguration der Datenquellen
7.3 Report-Umsetzer
7.4 Skript-Datenquelle
7.4
EIGENSCHAFT
BESCHREIBUNG
Ignoriere erste
Spalten der Zeilen
Anzahl der Spalten, die am Anfang jeder Zeile ignoriert werden sollen. Auf
einigen Host-Systemen werden in den ersten Zeichen jeder Zeile Steuerinformationen für den Druck gespeichert, die für den Datenimport irrelevant sind.
Ignoriere erste
Zeilen der Seite
Anzahl der Zeilen, die am Anfang jedes Dokuments ignoriert werden sollen
Umsetzung von
Feldern
In dieser Liste werden die Felder definiert, die aus der Quelldatei extrahiert und
an den Datenimport übergeben werden sollen. Es werden dafür rechteckige
Bereiche relativ zum Seitenanfang oder relativ zu einer Textmarke definiert.
skript-Datenquelle
Die Implementierung einer Datenquelle über ein Skript erlaubt die Anbindung sehr unterschiedlicher Datenquellen bzw. die Interpretation von Dateiformaten, die von den anderen Datenquellentypen nicht unterstützt werden.
Die Implementierung der Skripts kann unter Microsoft Windows in VBScript erfolgen, indem in einem SkriptObjekt oder einem Skript-Komponentenobjekt die folgenden Funktionen implementiert werden. Die Beispiele
zeigen die Implementierung eines Readers für spezielle XML-Dateien.
Im globalen Skriptbereich können allgemeine Initialisierungsaufgaben erledigt sowie Variablen deklariert und
initialisiert werden, die in mehreren Funktionen benötigt werden oder deren Werte über mehrere Aufrufe einer
Funktion hinweg erhalten bleiben sollen. Der globale Bereich wird beim Laden des Skripts einmalig durchgeführt.
149
Beispiel: Globaler Skriptbereich
'LANGUAGE="VBScript"
Dim xmldoc, xmlcustomer
Dim columnNames
Dim coort
Set coort = CreateObject("Coo.Runtime")
Set xmlcustomer = Nothing
Quelltext 3: Globaler Skriptbereich
Initialisierung
Die Funktion Init wird zu Beginn des Datenimports einmalig aufgerufen. Als Parameter wird der Wert der
Eigenschaft Tabelle aus dem Datenimportobjekt übergeben. Hier werden typischerweise Dateien geöffnet oder
Variablen gesetzt, die vom Wert der Tabellen-Eigenschaft abhängig sind.
Beispiel: Öffnen der XML-Datei
Function Init(table)
Set xmldoc = CreateObject("MSXML2.DOMDocument.6.0")
xmldoc.async = False
If xmldoc.load(table) Then
Set xmlcustomer = xmldoc.documentElement.firstChild
End If
End Function
Quelltext 4: Öffnen der XML-Datei
Die in der Eigenschaft Tabelle definierte XML-Datei wird mit dem XML-Parser geparst und die Variable, die den
aktuellen Datensatz enthält, auf den ersten Knoten der Liste gesetzt.
7. Konfiguration der Datenquellen
7.4 Skript-Datenquelle
Anfangsdatensatz
Diese Funktion muss nicht implementiert werden und wird genau dann einmal aufgerufen, wenn in der Eigenschaft Anfangsdatensatz ein Wert größer als „1“ eingetragen ist. Dann wird dieser Wert minus 1 als Parameter übergeben.
Beispiel: Überspringen von Datensätzen
Function Skip(rows)
Do While Not(xmlcustomer Is Nothing) And rows > 0
Set xmlcustomer = xmlcustomer.nextSibling
rows = rows – 1
Loop
End Function
Quelltext 5: Überspringen von Datensätzen
Im vorliegenden Beispiel wird die übergebene Anzahl von Knoten im XML übersprungen.
Spaltennamen
Auch die Funktion, in der die Spaltennamen berechnet werden, wird einmal aufgerufen und als Rückgabeparameter muss eine Liste von Spaltennamen definiert werden. Die Anzahl der Spalten muss mit der Anzahl der Werte übereinstimmen, die vom Skript später pro Datensatz gesetzt werden.
151
Beispiel: Berechnen der Spaltennamen
Function GetHeader(columns)
Redim columnNames(100)
Redim columns(100)
Dim columnCount, xmlnode
columnCount = 0
Set xmlnode = xmlcustomer.firstChild
Do While Not(xmlnode Is Nothing)
columnNames(columnCount) = xmlnode.nodeName
columns(columnCount) = xmlnode.nodeName
Set xmlnode = xmlnode.nextSibling
columnCount = columnCount + 1
Loop
Redim Preserve columnNames(columnCount - 1)
Redim Preserve columns(columnCount - 1)
End Function
Quelltext 6: Berechnen von Spaltennamen
In diesem Beispiel werden die Namen der Subelemente des ersten XML-Knotens als Namen für die Spalten verwendet.
Datensätze
Während der Verarbeitung wird die Funktion GetRecord solange immer wieder aufgerufen, bis entweder die
konfigurierte Anzahl der Datensätze erreicht ist, oder der Parameter IsValid dieser Funktion auf „False“
gesetzt wird. Im Parameter data wird ein String-Array übergeben, das im Skript mit den Werten eines Datensatzes befüllt werden muss. Ist das Ende der Daten erreicht, so muss der Parameter IsValid auf „False“
gesetzt werden, ansonsten auf „True“.
7. Konfiguration der Datenquellen
7.4 Skript-Datenquelle
Beispiel: Berechnen eines Datensatzes
Function GetRecord(data, isvalid)
If xmlcustomer Is Nothing Then
isvalid = False
Else
coort.Trace ""
For i = LBound(columnNames) To UBound(columnNames)
Set xmlnodelist = xmlcustomer.getElementsByTagName(columnNames(i))
If xmlnodelist.length > 0 Then
data(i) = xmlnodelist.item(0).text
coort.Trace columnNames(i) + ": " + data(i)
End If
Next
Set xmlcustomer = xmlcustomer.nextSibling
isvalid = True
End If
End Function
Quelltext 7: Berechnen eines Datensatzes
Hier werden die Werte der Subelemente der Knoten als Datenwerte der Spalten ausgelesen, die beim Aufruf
von GetHeader berechnet wurden.
Ende
Die Funktion Terminate kann implementiert werden um nach dem Lesen der Datensätze einen Status zu setzen, temporäre Dateien zu löschen oder andere Aufräumtätigkeiten durchzuführen. Zu diesem Zeitpunkt muss
aber die Verarbeitung der Datensätze noch nicht abgeschlossen sein. Es dürfen daher keine Aktionen angestoßen werden, die schon auf die Beendigung des Imports angewiesen sind.
153
Beispiel: Aufräumen des Imports
Function Terminate()
Set xmlcustomer = Nothing
Set xmldoc = Nothing
End Function
Quelltext 8: Aufräumen des Imports
Hier werden die XML-Ressourcen explizit freigegeben.
7.5
LDAP-Datenquelle
LDAP (Lightweight Directory Access Protocol) ist ein standardisiertes Protokoll für den Zugriff auf Directories,
wie zum Beispiel das Microsoft Active Directory oder OpenLDAP, die unter anderem für die Verwaltung von
Benutzerdaten und Gruppen verwendet werden. Mit der Anbindung von LDAP-Verzeichnissen ist eine automatisierte Übernahme und Aktualisierung von Log-in-Informationen aus dem Directory in die Benutzerverwaltung der
Fabasoft Components Domäne möglich.
Beispiel: Objekt im Directory
dn: cn=John Doe,dc=example,dc=com
cn: John Doe
givenName: John
sn: Doe
telephoneNumber: +1 888 555 6789
telephoneNumber: +1 888 555 1234
mail: [email protected]
manager: cn=Barbara Doe,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
7. Konfiguration der Datenquellen
7.4 Skript-Datenquelle
7.5 LDAP-Datenquelle
Die Objekte in einem Directory sind hierarchisch strukturiert und jeder Eintrag darin besteht aus mehreren Eigenschaften. Der Distinguished Name (dn) ist der Primärschlüssel für jeden Eintrag im Directory. Die Eigenschaften sind in einem Schema definiert und können auch mehrere Werte haben. Die Namen der Eigenschaften sind
gleichzeitig die Spaltennamen des Datenimports, mit der Ausnahme, dass die Spaltennamen um Formatierungsoptionen erweitert werden können, die zur Interpretation der Werte notwendig sein können.
Folgende Parameter werden für die Definition der Verbindung zum LDAP-Server unterstützt:
°
°
°
host: Hostname des Servers
°
°
°
°
°
searchbase: Basisverzeichnis für die Datenauswahl
port: TCP-Port für die Verbindung zum LDAP-Server
username/password: Accountname und Passwort für die Verbindung zum LDAP-Verzeichnis. Werden
diese Parameter unter Microsoft Windows nicht angegeben, wird „Integrated Authentication“ (über
Kerberos) für die Anmeldung verwendet.
timeout: Timeout für die Abfrage in Sekunden
sizelimit: Größenlimit für die Anfrage
pagesize: Maximale Anzahl der Werte pro Eigenschaft
dirsyncflags/dirsyncsize: Flags und Abfragegröße für die Synchronisation von Verzeichnissen
Beispiel: Verbindungsparameter LDAP-Datenquelle
host=FSPCOLD;
searchbase=OU=Test Users,DC=coldtest,DC=com;
timeout=100;
pagesize=300
Diese Konfiguration definiert die Übernahme von Datensätzen vom Host „FSPCOLD“. Es werden jene
Objekte übernommen, die in der Hierarchie unterhalb von der Organizational Unit „OU=Test
Users,DC=coldtest,DC=com“ liegen.
155
In der Tabelleneigenschaft werden die Einschränkungen bei der LDAP-Abfrage spezifiziert. Um Benutzerobjekte
zu laden ist das zum Beispiel „(objectClass=user)“.
In vielen Fällen müssen jedoch vor dem Laden der Daten Formatierungen durchgeführt oder Spalten berechnet
werden. Dafür ist das Filterskript für Rohdaten die richtige Stelle. Im Fall des Microsoft Active Directory wird
zum Beispiel aus dem Attribut userAccountControl das Bit für die Information ausgelesen, ob ein Benutzerkonto aktiv ist oder nicht. Dieses Skript finden Sie im Kapitel „Zusätzliche Beispiele“ auf Seite 159.
7.6
ADE DB
Seit kurzem stehen auch jene Datenbankanbindungen direkt für den Datenimport zur Verfügung, die von den
Fabasoft Components Services verwendet werden. Über diese ADE DB genannte Schnittstelle sind vor allem
die Datenbanksysteme Oracle (über die OCI-Schnittstelle) und PostgreSQL über deren datenbankspezifisches
Interface angebunden und können damit auch ohne Installation von ODBC- oder OLE DB-Treibern verwendet werden.
Die Parameter sind genau dieselben, wie sie auch für die Verbindungseinstellungen der Fabasoft Components
Backendservices zu den jeweiligen Datenbanken verwendet werden. Als Datenbank-Schnittstellen stehen damit
neben OLE DB und ODBC, die ja auch direkt als Datenquelle verwendet werden können, die Anbindung von
Oracle und PostgreSQL über deren eigenes Datenbank-API zur Verfügung. Somit kann jetzt mit derselben Datenbankkonfiguration des Backendservers auch der Datenimport durchgeführt werden.
Ein Unterschied zu den anderen Datenbank-Datenquellentypen ergibt sich dadurch, dass die ADE DB keine allgemeine Schnittstelle bietet, mit der die Datentypen der Spalten ermittelt werden können. Wenn bei den Zuordnungen die Option „Dateiname“ gesetzt ist, dann wird der Wert in eine Datei gespeichert, wenn die Option
„Inhalt als Wert“ gesetzt ist, dann wird eine Zeichenkette von 1 MB Größe verwendet, sonst werden generell
Zeichenketten mit 256 Zeichen verwendet. Werte die über diese Grenzen hinausgehen werden abgeschnitten.
7. Konfiguration der Datenquellen
7.5 LDAP-Datenquelle
7.6 ADE DB
7.7 CSV
7.8 Roll-Forward Log-Reader
7.7
cSV
Die Prinzipien der CSV-Dateien (Comma-Separated Values) wurden schon im Abschnitt über ODBC besprochen.
Seit Fabasoft Components Version 7 kann man CSV-Dateien auch ohne ODBC durch die Verwendung der
CSV-Datenquelle importieren.
7.8
Roll-Forward Log-Reader
Nicht als Datenquelle auszuwählen, aber dennoch von der Funktion wie eine Datenquelle ist der Roll-Forward
Log-Reader, der implizit verwendet wird, wenn der Menübefehl Roll-Forward zum Starten des Datenimports
verwendet wird. Der Roll-Forward Log-Reader liest die Daten aus dem Roll-Forward-Log, das im Protokollobjekt
hinterlegt ist und in dem die Daten jener Datensätze eingetragen sind, die beim letzten Datenimport nicht vollständig korrekt verarbeitet werden konnten.
Damit können, wenn Verarbeitungsfehler aufgetreten sind, konkret jene Datensätze noch einmal importiert werden, bei deren Verarbeitung die Fehler aufgetreten sind.
157
8
159
8 Zusätzliche Beispiele
Beim Importieren von Daten steht man bei jeder Migration immer vor ähnlichen Situationen,
wodurch die Wiederverwendung und Anpassung von konkreten Datenimporten, Filterskripts oder
Konfigurationen besonders wichtig ist. In diesem Kapitel finden Sie neben erklärenden Beispielen
auch einige Skripts, die von konkreten Migrationen abgeleitet sind und die leicht an Anforderungen
eines Datenimports angepasst werden können.
8.1
Datenquellenskript
XML-Datenquelle
In diesem Skript werden aus einer XML-Datei Datensätze importiert. Es wird dabei angenommen, dass in der
XML-Datei unter dem Wurzelknoten eine Liste von XML-Elementen angeführt ist und für jeden Knoten ein Datensatz erzeugt werden soll. Die Werte der Spalten stammen aus den Subelementen der einzelnen Listenknoten,
die Bezeichnungen aus den Elementnamen dieser Subelemente.
' LANGUAGE="VBScript"
Dim xmldoc, xmlcustomer
Dim columnNames
Dim coort
Set coort = CreateObject("Coo.Runtime")
Set xmlcustomer = Nothing
Function Init(table)
Set xmldoc = CreateObject("MSXML2.DOMDocument.6.0")
xmldoc.async = False
If xmldoc.load(table) Then
Set xmlcustomer = xmldoc.documentElement.firstChild
End If
End Function
Function GetHeader(columns)
Redim columnNames(100)
Redim columns(100)
Dim columnCount, xmlnode
columnCount = 0
Set xmlnode = xmlcustomer.firstChild
Do While Not(xmlnode Is Nothing)
columnNames(columnCount) = xmlnode.nodeName
columns(columnCount) = xmlnode.nodeName
Set xmlnode = xmlnode.nextSibling
columnCount = columnCount + 1
Loop
Redim Preserve columnNames(columnCount - 1)
Redim Preserve columns(columnCount - 1)
End Function
Function Skip(rows)
Do While Not(xmlcustomer Is Nothing) And rows > 0
Set xmlcustomer = xmlcustomer.nextSibling
rows = rows – 1
Loop
End Function
Function GetRecord(data, isvalid)
If xmlcustomer Is Nothing Then
isvalid = False
Else
coort.Trace ""
For i = LBound(columnNames) To UBound(columnNames)
Set xmlnodelist = xmlcustomer.getElementsByTagName(columnNames(i))
If xmlnodelist.length > 0 Then
data(i) = xmlnodelist.item(0).text
coort.Trace columnNames(i) + ": " + data(i)
End If
Next
Set xmlcustomer = xmlcustomer.nextSibling
isvalid = True
End If
End Function
Quelltext 9: Datensätze aus XML-Datenquelle importieren
8.2
Filterskript für Rohdaten
Berechnete Spalten
Gleich im Anfangskapitel wurde der Datenimport aus der Tabelle Customers der Datenbank Northwind
beschrieben. Darin trat das Problem auf, dass der ContactName sowohl Vor- als auch Nachname beinhaltet. Um diesen in zwei Teile zu zerlegen, wurde im ersten Ansatz eine SQL-View verwendet. Alternativ dazu kann
die Berechnung der beiden Werte auch in einem Filterskript für Rohdaten erfolgen.
8. Zusätzliche Beispiele
8.1 Datenquellenskript
8.2 Filterskript für Rohdaten
Dazu definiert man bei den Zuordnungen eine Zeile, in der nur die Spalte auf „CustomerName“ gesetzt ist aber
keine Objektklasse und keine Eigenschaft. Dadurch wird die Spalte zwar von der Datenquelle angefordert und
steht dem Filterskript zur Verfügung, es werden aber keine Zuordnungen von diesem Wert vorgenommen. Als
Spaltennamen für die Zuordnung zum Vor- bzw. Nachnamen setzt man „@CustomerFirstname“ bzw.
„@CustomerLastname“. Das „@“-Zeichen an der ersten Stelle des Namens bedeutet, dass die Spalte nicht aus
der Datenquelle stammt, sondern vom Filterskript für Rohdaten berechnet wird.
Nun aber zum Skript, das hier in zwei Versionen vorliegt, als VBScript und als JavaScript mit der gleichen Funktionalität.
' LANGUAGE="VBScript"
' Available global Variables:
'
coort (Components Runtime Object)
'
cootx (Components Transaction Object)
'
coolog (XMLLogWriter Object,
'
valid only if logging is not disabled)
' Define global variables holding the indexes
' of data columns
Dim ContactNameIdx, ContactFirstnameIdx, ContactLastnameIdx
' mark indexes as invalid
ContactNameIdx = -1
ContactFirstnameIdx = -1
ContactLastnameIdx = -1
' this procedure is called by the reader thread for
' each data record
Function Main(columns, data, changed, skip)
' Parameters:
'
columns: [IN] Array of Strings: column names
'
data:
[INOUT] Array of Strings: column data
'
changed: [OUT] Boolean: Set this flag to 'true' if
'
'data' has been changed
'
skip:
[OUT] Boolean: Set this flag to 'true'
'
to skip the whole record
Dim i, nameParts
If ContactNameIdx = -1 Then
For i = LBound(columns) To UBound(columns)
If columns(i) = "ContactName" Then
' Index of ContactName column
ContactNameIdx = i
ElseIf columns(i) = "@ContactFirstname" Then
' Index of ContactFirstname column
ContactFirstnameIdx = i
161
ElseIf columns(i) = "@ContactLastname" Then
' Index of ContactLastname column
ContactLastnameIdx = i
End If
Next
End If
If ContactNameIdx <> -1 And ContactFirstnameIdx <> -1 \
And ContactLastnameIdx <> -1 Then
nameParts = Split(data(ContactNameIdx), " ")
Select Case UBound(nameParts)
Case 1: ' ContactName consists of 2 words
data(ContactFirstnameIdx) = nameParts(0)
data(ContactLastnameIdx) = nameParts(1)
Case 2: ' ContactName consists of 3 words
If nameParts(1) = „de“ Then
data(ContactFirstnameIdx) = nameParts(0)
data(ContactLastnameIdx) = nameParts(1) + " " + \
nameParts(2)
Else
data(ContactFirstnameIdx) = nameParts(0) + " " +\
nameParts(1)
data(ContactLastnameIdx) = nameParts(2)
End If
Case Else
data(ContactLastnameIdx) = data(ContactNameIdx)
End Select
changed = True
Else
coolog.LogString "Index not found"
skip = True
End If
End Function
Quelltext 10: Filterskript für Rohdaten (VBScript)
Alternativ dazu das folgende JavaScript:
// LANGUAGE="JScript"
/*----------------------------Available global Variables:
coort (Components Runtime Object)
cootx (Components Transaction Object)
coolog (XMLLogWriter Object, valid only if logging is not disabled)
-----------------------------*/
8. Zusätzliche Beispiele
8.2 Filterskript für Rohdaten
// this procedure is called by the reader thread
// for each data record
/*----------------------------function MainEx(params)
Parameters:
params: [INOUT] Dictionary
params.values: Dictionary: Column values
params.changed: bool: Set this flag to 'true' if
'params.values' has been changed
params.skip:
bool: Set this flag to 'true' to skip
the whole record
-----------------------------*/
function MainEx(params)
{
var nameParts = params.values.ContactName.split(" ");
switch (nameParts.length) {
case 2:
params.values.SetEntryValue("@ContactFirstname", 0,
nameParts[0]);
params.values.SetEntryValue("@ContactLastname", 0,
nameParts[1]);
break;
case 3:
if (nameParts[1] == "de") {
params.values.SetEntryValue("@ContactFirstname", 0,
nameParts[0]);
params.values.SetEntryValue("@ContactLastname", 0,
nameParts[1] + " " + nameParts[2]);
}
else {
params.values.SetEntryValue("@ContactFirstname", 0,
nameParts[0] + " " + nameParts[1]);
params.values.SetEntryValue("@ContactLastname", 0,
nameParts[2]);
}
break;
default:
params.values.SetEntryValue("@ContactLastname", 0,
params.values.ContactName);
break;
}
params.changed = true;
}
Quelltext 11: Filterskript für Rohdaten (JavaScript)
163
Berechung der Werte aus der LDAP-Datenquelle
In dem folgenden Filterskript für Rohdaten werden aus der LDAP-Eigenschaft userAccountControl die Information extrahiert, ob das User-Objekt ein Computeraccount ist oder ob das Objekt inaktiv ist. Je nachdem wird
der Datensatz gänzlich ignoriert oder die Eigenschaft Aktiv auf „1“ oder „0“ gesetzt.
Außerdem werden aus den Werten der LDAP-Eigenschaft proxyAdresses E-Mail-Adressen im korrekten Format für die Eigenschaften in Fabasoft Components generiert.
' LANGUAGE="VBScript"
' Available global Variables:
'
coort (Components Runtime Object)
'
cootx (Components Transaction Object)
'
coolog (XMLLogWriter Object, valid only if logging is not disabled)
' global code and variables go here
Dim userAccountControl, dn, sAMAccountName, proxyAddresses, emailAddress,
emailKnownType
userAccountControl = -1
dn = -1
sAMAccountName = -1
proxyAddresses = -1
emailAddress = -1
emailKnownType = -1
Function Main(columns, data, changed, skip)
' Parameters:
'
columns: [IN] Array of Strings: column names
'
data:
[INOUT] Array of Strings: column data
'
changed: [OUT] Boolean: Set this flag to 'true' if 'data' has been
changed
'
skip:
[OUT] Boolean: Set this flag to 'true' to skip the whole
record
Dim cnpos, nextpos, esc
Dim lastDn, lastUserStatus
' this procedure is called by the reader thread for each data record
If userAccountControl=-1 Then
For i = LBound(columns) To UBound(columns)
If columns(i) = "userAccountControl" Then
userAccountControl = i
8. Zusätzliche Beispiele
8.2 Filterskript für Rohdaten
ElseIf columns(i) = "dn" Then
dn = i
ElseIf columns(i) = "sAMAccountName" Then
sAMAccountName = i
ElseIf columns(i) = "proxyAddresses" Then
proxyAddresses = i
ElseIf columns(i) = "@emailAddress" Then
emailAddress = i
ElseIf columns(i) = "@emailKnownType" Then
emailKnownType = i
End If
Next
End If
If userAccountControl > -1 Then
If Len(data(userAccountControl)) > 1 Then
If (CLng(data(userAccountControl)) AND 512) = 0 Then
skip = True
ElseIf (CLng(data(userAccountControl)) AND 2) = 0 Then
data(userAccountControl) = "1"
changed = True
Else
data(userAccountControl) = "0"
changed = True
End If
End If
End If
If skip = False AND dn > -1 AND sAMAccountName > -1 Then
If Len(data(dn)) > 1 AND Len(data(sAMAccountName)) > 0 Then
cnpos = InStr(data(dn), "DC=")
domain = ""
If cnpos > 0 Then
esc = False
cnpos = cnpos + 3
Do While cnpos < Len(data(dn))
If Not esc AND Mid(data(dn), cnpos, 1) = "," Then
Exit Do
Else
domain = domain + Mid(data(dn), cnpos, 1)
If Mid(data(dn), cnpos, 1) = "\" Then
esc = Not esc
Else
esc = False
End If
End If
cnpos = cnpos + 1
Loop
End If
165
If Len(domain) > 0 Then
data(sAMAccountName) = domain + "\" + data(sAMAccountName)
changed = True
End If
End If
End If
If skip = False And proxyAddresses > -1 AND emailAddress > -1 AND emailKnownType > -1 Then
If Len(data(proxyAddresses)) > 0 Then
addrs = Split(data(proxyAddresses), ":")
If UBound(addrs) = 1 Then
data(emailAddress) = addrs(1)
If LCase(addrs(0)) = "x400" Then
data(emailKnownType) = "2"
ElseIf LCase(addrs(0)) = "smtp" Then
data(emailKnownType) = "1"
End If
changed = True
End If
End If
End If
End Function
Quelltext 12: Filterskript zum Zugriff auf LDAP-Datenquelle
8.3
Filterskript für Objekte
Versionierung
Im folgenden Skript wird von jenen Objekten eine Version gezogen, die in der aktuellen Transaktion verändert
wurden, was durch den Aufruf der Funktion IsChanged ermittelt wird. Da gerade erzeugte Objekte nicht versioniert werden können, wird zusätzlich mit der Funktion IsCreated geprüft, ob die Objekte in dieser Transaktion erzeugt wurden.
8. Zusätzliche Beispiele
8.2 Filterskript für Rohdaten
8.3 Filterskript für Objekte
Es wird dabei das erste Objekt aus dem Parameter objects verwendet. Wenn mehrere Objekte an dem
Datenimport beteiligt sind, müssen die beiden Parameter classes und ids herangezogen werden, um das
richtige Objekt herauszufinden.
Selbst wenn zum Zeitpunkt des Aufrufs des Skripts die Eigenschaften bereits geändert sind, so wird von der Versionierung der Originalzustand des Objekts – als jener vor der aktuellen Transaktion – in der Version abgelegt.
Die Änderungen werden beim Commit in der aktuellen Version durchgeführt.
// LANGUAGE="JScript"
// Available global Variables:
//
coort (Components Runtime Object)
//
cootx (Components Transaction Object)
//
coolog (XMLLogWriter Object, valid only if logging is not disabled)
//
cootx is not the transaction that created the objects,
//
but the data main transaction of the data import
//
(equal to <cootx> in the filter for raw data)!
// global code and variables go here
function Main(classes, ids, objects, threadtx)
{
// Parameters:
//
classes: [IN] Array of Strings: object class references
//
ids:
[IN] Array of Integer: object class id’s
//
objects: [IN] Array of Components Objects
//
threadtx: [IN] Components Transaction Object of the writer thread
var obj = objects.toArray()[0];
if (obj) {
if (!threadtx.IsCreated(obj) && threadtx.IsChanged(obj)) {
obj.CallAction(threadtx, "ObjectFixVersion", false, "Datenimport");
}
}
}
Quelltext 13: Skript zur Versionierung
167
8.4
Filterskript für Objekte nach dem Commit
Archivierung
Ähnlich wie bei der Versionierung der Objekte im Filterskript für Objekte vor dem Commit, können Objekte
und Inhalte nach dem Commit auf ein Archiv gelegt werden. Hat man also vor, die importierten Daten sofort auf
ein Archiv auszulagern, um zum Beispiel Platz auf den Festplatten-Volumes der Fabasoft Components MMCServices zu schaffen, kann man das gleich nach dem Anlegen des Objekts im Filterskript für Objekte nach
dem Commit tun.
8. Zusätzliche Beispiele
8.4 Filterskript für Objekte nach dem Commit
169
9
171
9 Glossar
Aggregat
Seite 49
Eine Zusammenfassung von mehreren Eigenschaften zu einer großen Containereigenschaft, die auch als Liste
dargestellt werden kann. Ein Aggregat, oder auch zusammengesetzte Eigenschaft genannt, ist ein Container für
mehrere Formularblockelemente. Ein Aggregat entspricht einem Formularblock.
Seite 79
Archivierung
Unter Archivierung wird die Ablage und das Wiederbeschaffen von Informationen in IT-Systemen verstanden.
Seite 48
Archivstore
Um das Archivsystem verwenden zu können, muss in Fabasoft Components mindestens ein Objekt der Klasse
Archiv-Store definiert werden, welches einen Verzeichnispfad zur Archivierung von Geschäftsobjekten angibt.
AT-Service
Seite 75
Am AT-Server laufen die Fabasoft Components AT-Services für die Durchführung automatischer Aufgaben(Automated Tasks) im Kontext eines Benutzers ohne Benutzerinteraktion ab.
Get-Aktion
Bezeichnet die bei einer Eigenschaft hinterlegte Aktion nach dem Lesen der Eigenschaft.
Seite 44
Seite 67
Indizierung
Das automatische Speichern von in Dateien im Dateisystem enthaltenen Texten und Metadaten in einem Index.
Dieses Verfahren erlaubt eine schnelle Suche in den Inhalten von Dateien, da nicht in den Dateien selbst,
sondern im Index nach dem Suchbegriff gesucht wird.
Komponentenobjekt
Seite 21
Objekt, das von einer bestimmten Objektklasse abgeleitet ist und Konfigurationsdaten enthält. Komponentenobjekte werden zu Softwarekomponenten zusammengefasst.
Migrationszwischenformat
Seite 96
Dieser Begriff wird im Zusammenhang mit der Ablösung von Altsystemen und Übernahme von Daten (Migrationen) verwendet. Beim Migrationszwischenformat handelt es sich um eine vorgegebene Datenstruktur in einer
relationalen Datenbank. Mit Hilfe der Fabasoft Components/COLD-Technologie werden die Daten dann aus dem
Migrationszwischenformat in eine Fabasoft Components Domäne geladen.
Seite 61
Objektadresse
Jedes Objekt in einer Fabasoft Components Domäne hat eine Objektadresse. Diese ist weltweit eindeutig.
Seite 44
Set-Aktion
Bezeichnet eine Aktion, die beim Setzen eines Eigenschaftswertes ausgeführt wird. Eine derartige Aktion kann
direkt bei der Eigenschaft eingetragen werden.
Transaktion
Seite 28
Eine Abfolge von mehreren Operationen, die entweder alle oder gar nicht durchgeführt werden müssen. Erfolgt
in einer Operation ein Fehler, müssen alle zuvor durchgeführten Änderungen wieder rückgängig gemacht
werden. Werden alle Operationen ohne Fehler durchgeführt, so können alle Änderungen übernommen werden.
Seite 83
TriStep
Spezielle Ausprägung eines Objektkonstruktors. Ist der Konstruktor einer Objektklasse als TriStep implementiert,
wird beim Erzeugen einer neuen Objektinstanz die Aktion [email protected]:PreGUI aufgerufen und
anschließend das für diese Objektklasse definierte Konstruktorformular angezeigt. Nach dem Schließen des
Konstruktorformulars durch den Benutzer wird die Aktion [email protected]:PostGUI ausgeführt.
Webbrowser-Client
Seite 88
Unter einem Webbrowser-Client wird in diesem Buch ein Arbeitsplatzrechner (PC-Arbeitsplatz) mit Betriebssystem (z.B. Microsoft Windows), Webbrowser (Mozilla Firefox oder Microsoft Internet Explorer) und entsprechender Anwendungssoftware (z.B. OpenOffice.org oder Microsoft Office) verstanden.
9. Operations Manager Log
173
Wrapper-Aktion
Seite 116
Eine Aktion, die vor bzw. nach der Ausführung der eigentlich aufgerufenen Aktion ausgeführt wird. Pre-Wrapper
werden vor der Ausführung der aufgerufenen Aktion ausgeführt, Post-Wrapper nach deren Ausführung.
10
175
10 Abbildungsverzeichnis
Abbildung 1
Abbildung 2
Abbildung 3
Abbildung 4
Abbildung 5
Abbildung 6
Abbildung 7
Abbildung 8
Abbildung 9
Abbildung 10
Abbildung 11
Abbildung 12
Abbildung 13
Abbildung 14
Abbildung 15
Abbildung 16
Abbildung 17
Abbildung 18
Abbildung 19
Abbildung 20
Abbildung 21
Abbildung 22
Abbildung 23
Customers: Datenquelle und Zuordnungen
Customers: Objektbeziehungen und Klasseneigenschaften
Customers: Daten importieren
Datenfluss bei der Verarbeitung eines Datenimports
Zuordnungen mit Spaltenansicht
Objektbeziehungen mit Spaltenansicht
Kasseneigenschaften mit Spaltenansicht
Einstellungen und Optionen des Datenimports
Protokollobjekt
Skripts des Datenimports
Schlüssel und Änderungsmodus
Definition mehrerer Listeneinträge pro Datensatz
Methoden zur Vermeidung doppelter Objekte
Auswahl der Suchmethoden
Verarbeitung der Datensätze im Worker Thread
Optimierungsoptionen des Datenimports
Auswahl einer ODBC- bzw. OLE DB Datenquelle
Auswahl der Tabelle und der Spalten
Definition eines Datenbereichs in Microsoft Excel
Definition einer OLE DB-Datenquelle
Konfiguration der OLE DB-Quelldatenbank
Konfiguration eines Imports mit OLE DB File Provider
Konfiguration des Report-Umsetzers
22
23
24
27
32
33
34
35
36
38
43
53
58
65
78
98
133
134
136
140
141
146
147
11
177
11 Literaturverzeichnis
[Gorh06]
Gorham, Nick: „The unixODBC Project home page“. URL: http://www.unixodbc.org
[Stand: 4.6.2007].
[MoNo03]
Morle, James/Nørgaard, Mogens: „BAARF: Enough is enough“.
URL: http://www.miracleas.com [Stand: 4.6.2007].
[MSDN04]
Microsoft Developer Network: „Schema.ini File (Text File Driver)“.
URL: http://msdn.microsoft.com/library/default.asp?url=/library/
en-us/odbc/htm/odbcjetschema_ini_file.asp [Stand: 4.6.2007].
[Orac07]
Oracle Technology Network: „Instant Client Downloads for Linux x86“.
URL: http://www.oracle.com/technology/software/tech/oci/
instantclient/htdocs/linuxsoft.html [Stand: 4.6.2007].
Herunterladen
Explore flashcards