Datenbankauswahl

Aus Limbas Wiki

Wechseln zu: Navigation, Suche

<-- zurück zu Kurzanleitungen / <-- zurück zur Hauptseite-Portale


LIMBAS und die Wahl der Datenbank

LIMBAS als Datenbankfrontend hat bislang nur die ADABAS-D bzw. SAPDB oder MAXDB Datenbank unterstützt. Seit Version 2.0 bietet LIMBAS die Möglichkeit sich die Datenbank auszusuchen. Voraussetzung dafür ist ein ODBC Treiber und eine Reihe von Datenbank spezifischen Anpassungen. Dieser Artikel soll anhand von MAXDB und PostgreSQL die Unterschiede beider Datenbanken beleuchten, sowie eine Vorlage für die Migration anderer Datenbanken in LIMBAS bieten.

Anbindung

Die Anbindung der Datenbank erfolgt in PHP über die ODBC Erweiterung. Dafür kann der jeweilige ODBC Treiber direkt in PHP einkompiliert werden oder man nutzt Unix-ODBC als Zwischenschicht. Unix-ODBC hat den Vorteil, dass es über PHP-Module leicht installiert werden kann und nur noch seine Konfigurationsdateien angepasst werden müssen. Der gemessene Geschwindigkeitsverlust gegenüber der direkten Verbindung kann bei LIMBAS als minimal eingestuft werden und wirkt sich erst bei hohen Lasten negativ aus. Ein späterer Wechsel der Verbindungsart ist ohne Probleme möglich.

[PSQL]
Description=PostgreSQL
Driver=/usr/lib/psqlodbcw.so
Setup=/usr/lib/unixODBC/libodbcpsqlS.so

Treiberdefinition von UnixODBC in der odbcinst.ini

Einbinung

Welche Datenbank LIMBAS nutzen soll ist in der Datei dependent/inc/include.db der LIMBAS Quellen definiert. Diese Datei beinhaltet nicht nur die Zugangsinformationen zur jeweiligen Datenbank, sondern definiert auch den Pfad zu den Integrationsdateien. Der Pfad setzt sich aus der Globalen $DBA['DB'] und dem Verzeichnispfad lib/db zusammen. Pro Datenbank gibt es jeweils zwei Dateien. Die erste ist für die Verbindung der Datenbank, für die allgemeine Beschreibung der Datentypen und für ein paar grundsätzliche Funktionen zuständig. Die zweite behandelt Admin-Funktionen wie Trigger, Foreign Keys oder Indexes und steht ausschließlich LIMBAS Benutzern zur Verfügung, die Admin-Rechte besitzen. Für PostgreSQL wäre das die lib/db/postgres.lib bzw. lib/db/postgres_admin.lib.

Für das Einbinden einer neuen Datenbank wie Beispielsweise MYSQL müssen wir nur die zwei Integrationsdateien einer vorhandenen Datenbank kopieren und in db_mysql.lib und db_mysql_admin.lib umbenennen, sowie die Globale $DB['DB'] anpassen.

$DBA["DB"] = 'postgres';		/* maxdb76 | postgres | ingres */
$DBA["DBCUSER"] = 'CONTROLUSER'; 	/* DB control user (only MAXDB)*/
$DBA["DBCPASS"] = 'CONTROLPASS'; 	/* DB control password (only MAXDB)*/
$DBA["DBUSER"] = "limbasuser";		/* DB username */
$DBA["DBPASS"] = "xavuser";		/* DB password */
$DBA["DBNAME"] = "limbas";		/* DB instance name */
$DBA["DBSCHEMA"] = "public";		/* DB schema */
$DBA["DBHOST"] = "localhost";		/* DB hostname or IP */
$DBA["LMHOST"] = "localhost";		/* LIMBAS hostname or IP */
$DBA["DBPATH"] = "/opt/sdb/programs/bin";	/* Path to database */
$DBA["LMPATH"] = "/usr/local/httpd/htdocs/limbas_2/dependent";	/* 
Path to  LIMBAS */
$DBA["ODBCDRIVER"] = "PSQL";		/* unixODBC Driver */
require_once("{$DBA['LMPATH']}/lib/db/db_{$DBA['DB']}.lib");

inc/include_db.lib

LIMBAS Core

Für den Fall von MAXDB, PostgreSQL und Ingres ist außer der Anpassung der zwei Dateien kein Eingriff in den LIMBAS Core notwendig. Für weitere Datenbanken ergeben sich möglicherweise notwendige Erweiterungen. Ein aktuelles Beispiel zeigt die MYSQL. LIMBAS geht aktuell davon aus, dass mehrere DEFAULT TIMESTAMP Definitionen pro Tabelle möglich sind, was MYSQL so nicht unterstützt. Eine Änderung des LIMBAS Cores wäre somit notwendig. Ein weiteres Beispiel ist die Ingres, welches den Datentyp BOOLEAN nicht kennt. Der LIMBAS Core musste in diesem Fall die Möglichkeit bieten anstatt BOOLEAN ein Zahlenfeld mit den Werten 0 und 1 zu nutzen. Eine Abwägung von Nutzen und Aufwand sollte also vor jeder Entscheidung für eine Integration einer Datenbank stehen.

Anpassung

Nun wenden wir uns der eigentlichen Integration zu. In unserem Beispiel beschreiben wir die Einbindung der PostgreSQL Datenbank. Dafür schauen wir uns zuerst die allgemeine Integrationsdatei db_postgres.lib etwas genauer an.

Im ersten Teil der Datei finden wir eine Reihe von Konstanten. Diese Konstanten sind für die unterschiedliche Behandlung der Datentypen und der SQL Interpretation zuständig. Dabei werden die Konstanten durch ihren Namensanfang nach ihrer Aufgabe unterschieden.

LMB_DBTYPE_?
Diese Konstanten definieren den entsprechenden Datentypen der Datenbank. Als Referenz wurden aus historischen Gründen die Datentypen der MAXDB genommen.

Example: define("LMB_DBTYPE_LONG","TEXT"); bedeutet, dass der entsprechende Datentyp für LONG für die PostgreSQL Datenbank TEXT ist.


LMB_DBDEF_?
Hiermit werden die Defaultwerte definiert.

Example: define("LMB_DBDEF_TIME","CURRENT_TIME"); Was soviel bedeutet wie: nutze als Defaultwert für den Zeitwert CURRENT_TIME


LMB_DBRETYPE_?
Diese Konstante wird genau umgekehrt wie LMB_DBTYPE_? definiert. Hier ist ihr Name die Definition und ihr Wert die Referenz.

Example: define("LMB_DBRETYPE_TEXT","LONG"); Diese Konstante wird für die Auflösung der Datentypen aus einem Export der Datenbank benötigt. Somit ist es möglich in LIMBAS einen allgemein gültigen Export zu generieren, welcher wieder in eine andere LIMBAS Installation mit einer ganz anderen Datenbank importiert werden kann.


LMB_DBREDEF_?
Auch für LMB_DBDEF_? gibt es eine Konstante, die durch ihren Namen die Definition des Default-Wertes beschreibt.

Example: define("LMB_DBREDEF_NOW()","DEFAULT TIMESTAMP"); In diesem Fall bringt PostgreSQL als Defaultwert für einen TIMESTAMP den Wert NOW().


LMB_DBFUNC_?
Als letztes werden funktionale Konstanten beschrieben. Der Name ist frei erfunden.

Example: define("LMB_DBFUNC_YEAR","EXTRACT(YEAR FROM ");

Die Abfrage nach dem Jahr in einem SQL Aufruf eines Feldes des Typs TIMESTAMP würde für PostgreSQL SELECT EXTRACT(YEAR FROM ZEITWERT) lauten. Für MAXDB hingegen genügt ein einfaches SELECT YEAR(ZEITWERT). Ein kompletter SQL Aufruf zum Erstellen einer Tabelle würde somit folgendermaßen aussehen:

CREATE TABLE TEST (ID [LMB_DBTYPE_INTEGER] [LMB_DBFUNC_UNIQUE], NAME [LMB_DBTYPE_VARCHAR](150), ERSTELLT [LMB_DBTYPE_TIMESTAMP] DEFAULT [LMB_DBDEF_TIMESTAMP] PRIMARY KEY [LMB_DBFUNC_PRIMARY_KEY] ID)

Sind die Unterschiede der SQL Aufrufe zu unterschiedlich und die Anforderung durch einfache Konstanten nicht mehr umsetzbar, werden Funktionen eingesetzt, welche im zweiten Teil der db_postgres.lib definiert sind.
Diese Funktionen sind recht einfach gehalten und erklären sich von selbst:

  • Die erste Funktion ist die Funktion dbq_0. Sie beinhaltet die eigentliche ODBC Verbindung. Optional ist der Gebrauch von CURSOR Einstellungen. Bei manchen Datenbanken ist ein scrollable cursor kein Standard und muss explizit angegeben werden. Ein scrollable cursor erlaubt ein Blättern in beide Richtungen durch das Abfrage Ergebnis. Anderenfalls würde ein zweimaliges Abfragen des gleichen Datensatzes oder eine explizite Angabe der Ergebniszeile über odbc_fetch_row() kein Ergebnis bringen. Die Einstellung erfolgt über den php.ini Wert odbc.default_cursortype.
  • Die Funktionen dbf_1 und dbf_2 konvertieren das Format des Datums für und von der Datenbank. In der Regel haben Datumsfelder ohne besondere lokale Einstellungen der Datenbank das Format YY.MM.DD. Zu beachten ist, dass sich ausschließlich LIMBAS um die Konvertierung des Datums kümmert und nicht von der Datenbank behandelt werden sollte. Ein gutes Beispiel ist das standardmäßige Lokalisierungsverlangen von PostgreSQL. Bei der Installation der Datenbank sollte man deshalb auch die Option initdb –local=C, welche einen nicht lokalisierten Datenbankcluster erzeugt, nutzen.
  • Die Funktionen dbf_6 und dbf_7 kümmern sich um die Maskierung von Sonderzeichen. Meistens genügt eine Behandlung des Hochkommas (') durch Voranstellung des selbigen (). PostgreSQL akzeptiert auch einen Backslash (\) was mit der PHP Funktion addslashes() einfach bewerkstelligt werden kann. Durch die Sonderstellung des Fragezeichens (?) können damit aber auch Probleme auftreten. Der SQL Aufruf UPDATE TEST SET TEXTFELD = 'der \'Hund?\' Hat Flöhe' , was soviel bedeutet wie "der 'Hund?' hat Flöhe" verursacht in PostgreSQL folgenden Fehler "The # of binded parameters < the # of parameter markers". Besser ist der Aufruf: UPDATE TEST SET TEXTFELD = 'der Hund? Hat Flöhe'. Da sich LIMBAS um die Maskierung von SQL Aufrufen kümmert und nicht zuletzt, da die Funktion in kommenden PHP Versionen entfernt werden soll, sollte die serverseitige Maskierung von PHP via magick_quotes ausgeschaltet sein.
  • Weitere größere Unterschiede finden sich in der Behandlung von LONG Feldern. Wie bei den meisten Datenbanken wurden LONG oder BLOB Felder erst im nach hinein implementiert. Dadurch entstanden einige Einschränkungen, was die Nutzung dieses Feldtyps anbelangt. MAXDB erlaubt beispielsweise keine LONG Felder im Zusammenhang mit DISTINCT oder ORDER BY Aufrufe. Ebenso kann man LONG Felder nicht per SQL Aufrufe durchsuchen. Ein UPDATE eines LONG Feldes ist nur über den Umweg eines odbc_prepare statements möglich. Da LIMBAS historisch über die ADABAS-D bzw. SAPDB entstanden ist, existiert für diese Felder eine eigene Indizierungsfunktion, welche das Durchsuchen dieser Felder wieder möglich macht. Bei PostgreSQL gestaltet sich das wiederum deutlich einfacher. TEXT Felder können wie normale VARCHAR Felder behandelt werden. Trotzdem kann auch hier die Indizierungsfunktion von LIMBAS genutzt werden, falls es gewünscht ist. Je nach Größe und Menge der Inhalte kann die eine oder andere Weise ihre Vorteile haben. Die gleiche Indizierungsfunktion nutzt LIMBAS übrigens auch um das integrierte Dateisystem zu verschlagworten. Ingres hat ähnlich zu MAXDB einige Einschränkungen, was den Datentyp LONG anbelangt, bietet aber dafür extrem lange VARCHAR Felder (30000 Zeichen).
  • Nicht zu unterschlagen ist auch die Nutzung von FLOAT Feldern. Diese sind, wie der Name schon sagt, Fließkomma Zahlen und somit „ungenau“. Im Allgemeinen ist dieser Feldtyp also sicher nicht für Währungen geeignet. Interessanterweise konnte diese Ungenauigkeit bei MAXDB so nicht beobachtet werden, wohingegen in PostgreSQL die interessantesten Rundungen entstanden sind. Welche Feldtypen intern verwendet werden sollen ist in der LIMBAS Systemtabelle lmb_fieldtypes.
  • Die letzte Funktion ist für die Groß-Kleinschreibung der Tabellen oder Feldnamen in der Datenbank zuständig. Obwohl fast alle Datenbanken das frei definierbar lassen und der SQL Standard eine Groß-Schreibung vorgibt, sind in PostgreSQL, MYSQL und Ingres die Namen standardmäßig alle klein geschrieben. Diese kleine Funktion erspart dem Administrator notwendige Anpassungen an der Datenbank.

Nach dieser kleinen Aufwärmung kommen wir zur zweiten Integrationsdatei db_postgres_admin.lib, welche wir allerdings nur oberflächlich behandeln werden. Diese Datei beinhaltet alle Funktionen, die für die Admin-Werkzeuge, wie zum Beispiel Trigger verwalten, Foreign Keys erstellen, Backup erzeugen usw., notwendig sind. Wo in der Definition der Feldtypen oder der Umsetzung von Standard SQL noch einigermaßen Konformität herrschte, ist dieser Bereich deutlich spezifischer gehalten. Ein gutes Beispiel ist die Abfrage nach allen Indexes inklusive ihrer Verweise, Primary Keys und Informationen, die zum Nachbau in einer anderen Datenbank notwendig sind. Für MAXDB genügt in diesem Fall ein einfacher SQL Aufruf : SELECT * FROM DOMAIN.INDEXCOLUMNS , wo hingegen für PostgreSQL geradezu ein Feuerwerk einer Systemtabellen-Abfrage notwendig ist:

SELECT c.oid,
    n.nspname,
    c.relname AS TABLENAME,
    c.relhasindex, c.relkind, c.relchecks, c.relhasrules, c.relhasoids,  c.reltablespace,
    a.attname AS COLUMNNAME,
      pg_catalog.format_type(a.atttypid, a.atttypmod) AS TYPE,
   (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
       FROM pg_catalog.pg_attrdef d
       WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) as attrdef,
     a.attnotnull, a.attnum,
     i.indexrelid,
     i.indrelid,
     i.indisunique, i.indisprimary, i.indisclustered, i.indisvalid AS INDEX_VALID, i.indisready AS INDEX_USED,
     c1.relname AS INDEXNAME
FROM pg_catalog.pg_class c
   LEFT JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
   LEFT JOIN pg_catalog.pg_index AS i ON i.indrelid = c.oid
   LEFT JOIN pg_attribute AS a ON a.attrelid = i.indexrelid
   LEFT JOIN pg_catalog.pg_class c1 ON i.indexrelid = c1.oid
WHERE c.relhasindex = true
   AND c.relname not like '%pg_%'
   AND a.attnum > 0 AND NOT a.attisdropped
   AND pg_catalog.pg_table_is_visible(c.oid)

Insgesamt werden in dieser Datei foreign keys, primary keys, indexes, trigger, views, tables, columns, stored procedures, und backups behandelt.

Geschwindigkeit

Ein Vergleich der Geschwindigkeit von LIMBAS in Verbindung der eingesetzten Datenbanken ist ein Auf und Ab der Gefühle. Eine Festlegung, welches die schnellere Alternative ist, wäre in unseren Augen schwer zu erklären. Jede Datenbank hat in bestimmten Situationen erstaunlichen Abstand zum Konkurrenten. Und das gilt für beide Richtungen. Es ist ein Zusammenspiel von Komplexität des SQL Aufrufs und Größe der Datenbank was ganz unterschiedliche Ergebnisse liefert. Ebenso tragen die von Haus aus notwendigen Hardware-Ressourcen stark zur Leistungsfähigkeit bei. Wo die MAXDB geradezu Speicher verschlingt, begnügt sich PostgreSQL oft mit weniger, was bei hoher Auslastung allerdings wieder MAXDB besser nutzen konnte.

Fazit

Die in LIMBAS integrierten Datenbanken MAXDB, postgreSQL und Ingres sind alle eine hervorragende Wahl. Das betrifft die Leistungsfähigkeit, sowie Ihre Kompatibilität zu LIMBAS. MAXDB zeichnen ihre professionellen Management Tools, sowie das ausgezeichnete Backup aus. Ebenso war sie im bisherigen Einsatz mit LIMBAS immer sehr stabil und nur selten aus der Fassung zu bringen. Mankos sind die magere LONG Unterstützung und die ungewisse Zukunft der Datenbank. PostgreSQL hat seinen Vorteil klar in seiner schlankeren Struktur. Das zahlt sich in einer einfachen Installation, sowie einer hohen Geschwindigkeit auch bei schwachen Rechnern aus. Größtes Manko aus unserer Sicht ist das Backup-Konzept.

Es bleibt also dem Nutzer zu entscheiden, welche Datenbank für seine Zwecke die bessere Wahl ist. Durch die grundsätzlich einfache Portierung der Datenbank in LIMBAS bleibt es aber immer frei, die Datenbank zu wechseln.