Artikel - Detailansicht

Icon Aktuelles Die Nutzung transaktionsbehafteter Tabellen in MySQL mit Cold Fusion

von: Kai König

msg at.net GmbH, Marienkirchplatz 3, 41460 Neuss, Deutschland
koenig@msg-at.net, http://www.msg-at.net

Download des gesamten Artikels als PDF

Zusammenfassung
Transaktionen sind zentrale Elemente geschäftskritischer datenbankbasierter Applikationen im WWW. Bislang war es nicht möglich, Transaktionen in Web-Applikationen mit Cold Fusion zu verwenden, denen das freie DBMS MySQL zugrunde liegt. Dieser Artikel zeigt auf, in welchem Maße sich die Situation mit der Einführung neuer Tabellentypen in MySQL 3.23 verbessert hat und wie man die Fähigkeiten der transaktionsbehafteten Tabellen mit dem Applikationsserver Cold Fusion in der Version 5 nutzen kann.

Inhalt
1 Einleitung
2 MySQL-Tabellentypen
2.1 MyISAM
2.2 BDB
2.3   InnoDB
3 MySQL-Konfiguration
4 Transaktionen
4.1 Besonderheiten in BDB-Tabellen
4.2 Besonderheiten in InnoDB-Tabellen
5 Transaktionsunterstützung in Cold Fusion
6 Beispiele
6.1 Einfache Transaktion um mehrere CFQUERY-Tags
6.2 Transaktionsende abhängig von externen Ereignissen
6.3 Transaktionen zum Zweck des Debuggings einer Serie von SQL-Statements
7 Benchmarks und verwendete Infrastruktur
7.1 MyISAM
7.2 BDB
7.3 InnoDB
8 Mögliche Probleme und nicht behandelte Themen
9 Fazit


1 Einleitung

Transaktionen stellen sicher, dass eine Gruppe von SQL-Kommandos entweder vollständig oder nicht ausgeführt wird. Dazu stellt man den betreffenden Kommandos den Befehl BEGIN voran und beendet die Befehlssequenz üblicherweise entweder mit dem Befehl COMMIT oder mit dem Befehl ROLLBACK. Ein beliebtes Anwendungsbeispiel für die Notwendigkeit von Transaktionen ist die überweisung eines Geldbetrages von einem Konto auf ein anderes. Es darf dabei nicht passieren, dass zwar eine Abbuchung vom Ursprungskonto stattfindet, aber keine Gutschrift auf dem Zielkonto durchgeführt wird.

Eine weitere Aufgabe von Transaktionen ist es, sicherzustellen, dass Daten nicht zeitgleich von konkurrierenden Anwendern verändert werden können. Das ist erforderlich, um die referentielle Integrität einer Datenbank zu gewährleisten. Eine Lösung dieses Problem liegt bislang darin, LOCK-Befehle auf die MySQL-Datenbank abzusetzen, was allerdings kurzzeitig ganze Tabellen für den Zugriff anderer Clients sperrt Offensichtlich ist dieser Ansatz im produktiven Betrieb sehr ineffizient. Die neueren Versionen des MySQL-DBMS bieten transaktionstaugliche Tabellentypen, bei deren Nutzung wirklich ausschließlich die Datensätze gesperrt werden, die sich tatsächlich in Bearbeitung befinden.


2 MySQL-Tabellentypen

Die Unterstützung von Transaktionen ist in MySQL nicht standardmäßig vorhanden. Entscheidend für die Fähigkeit, mit Transaktionen umgehen zu können, ist der verwendete Tabellentyp; der Default-Tabellentyp ist MyISAM und hat keine Transaktionsfähigkeit. In der aktuellen Version 3.23.49 werden zusätzlich die Tabellentypen BDB, InnoDB und Gemini unterstützt, welche transaktionsfähig sind [2, Kapitel 7].

Der in MySQL verwendete Ansatz, einzelne Tabellen in einem der neuen Tabellentypen erzeugen zu können, ermöglicht es je nach Anwendungsfall in einer Datenbank Tabellen verschiedenen Formates einzusetzen. Mit einem einfachen SQL-Statement kann man feststellen, welche Tabellentypen in der verwendeten MySQL-Installation unterstützt werden:

SHOW VARIABLES LIKE 'have_%'

Dieser Befehl liefert eine Auflistung verschiedener Server-Variablen:

have_bdb YES
have_gemini NO
have_innodb YES
have_isam YES

Dabei werden die Ergebnisse YES, NO oder DISABLED zurückgeliefert. Letzteres bedeutet, dass der entsprechende Tabellentyp zwar generell unterstützt wird, aber im konkreten Fall Konfigurationsprobleme vorliegen.


2.1 MyISAM

MyISAM stellt den Default-Tabellentyp in MySQL dar. Um Mechanismen zur Zugriffskontrolle zu implementieren, kann man nur gesamte Tabellen durch LOCK schützen.


2.2 BDB

In BDB-Tabellen werden im Rahmen einer Transaktion automatisch alle erforderlichen Datensätze blockiert. Ein Nachteil dieses Tabellentyps hinsichtlich der Transaktionsarchitektur ist allerdings, dass intern ganze Speicherseiten gesperrt werden. Je nach Grösse der Tabelle und Konfiguration des DBMS sind daher in der Regel auch Datensätze im direkten Umfeld der eigentlich gesperrten Datensätze nicht mehr zugänglich.


2.3 InnoDB

InnoDB-Tabellen verhalten sich grundsätzlich analog zu BDB-Tabellen, auch hier werden also im Rahmen von Transaktionen benutzte Datensätze automatisch gesperrt. Allerdings ist das Locking-Verhalten bei InnoDB-Tabellen einerseits feiner regulierbar als bei BDB-Tabellen, andererseits werden in der InnoDB-Architektur ausschließlich die betroffenen Datensätze gesperrt.


3 MySQL-Konfiguration

Zur Nutzung der neuen Tabellentypen muss die so genannte MySQL-Max-Version eingesetzt werden. Zur Installation der entsprechenden Binaries sei auf [1] und [2, Kapitel 2] verwiesen. Unter den oben genannten Voraussetzungen lassen sich MyISAM- und BDB-Tabellen problemlos verwenden.

Die Installation von InnoDB-Tabellen setzt die Existenz spezieller Verzeichnis- und Dateistrukturen voraus, da diese Tabellentypen nicht wie MyISAM- und BDB-Tabellentypen in einfachen Dateien im MySQL-Datenverzeichis hinterlegt werden, sondern hier ein zentraler Tablespace angelegt wird, der als Speicherort für InnoDB-Tabellen und -Indizes dient. Die Einrichtung dieser Strukturen erfolgt über Einstellungen in der Datei my.cnf.

Hier eine beispielhafte Konfiguration für eine Maschine mit ca. 128-192 MB Hauptspeicher und zwei je 100 MB großen Dateien, die den InnoDB-Tablespace bilden:

innodb_data_home_dir = c:\mysql\innodata\
innodb_data_file_path = ibdata1:100M;ibdata2:100M
set-variable = innodb_buffer_pool_size=70M
set-variable = innodb_additional_mem_pool_size=10M
innodb_log_group_home_dir = c:\mysql\iblogs\
innodb_log_arch_dir = c:\mysql\iblogs\
innodb_log_archive=0
set-variable = innodb_log_files_in_group=3
set-variable = innodb_log_file_size=10M
set-variable = innodb_log_buffer_size=8M
innodb_flush_log_at_trx_commit=1
set-variable = innodb_file_io_threads=4
set-variable = innodb_lock_wait_timeout=50

Bei dieser Konfiguation ist zu beachten, dass die entsprechenden Pfade manuell angelegt werden müssen. Eine Erläuterung der einzelnen Parameter findet man in [2, Kapitel 7.5.2].

Die angelegten Dateien für den Tablespace können nachträglich nicht mehr hinsichtlich ihrer Größe verändert werden. Benötigt man mehr Platz, muss man im zweiten oben angegebenen Parameter weitere Dateien mit entsprechenden Größenangaben hinzufügen. Der einzige Weg zur Verkleinerung des Tablespace ist ein Export der Tabellen in einen neuen, verkleinerten Tablespace mit mysqldump.

Wichtig ist weiterhin die Nutzung der binären Logging-Mechanismen von MySQL, da nur so gewährleistet ist, dass Transaktionen korrekt behandelt werden. Das binäre Logging schaltet man auch über Einträge in der Datei my.cnf ein:

log=on
log-bin=on


4 Transaktionen

Transaktionsfähige Tabellen werden in MySQL mit einem CREATE-Statement erzeugt:

CREATE TABLE Kunde
(KundeId INT AUTO_INCREMENT, KundeName VARCHAR(255), KundeVorname VARCHAR(255),
  Primary Key (KundeId))
TYPE=BDB

Entscheidend ist hier der abschließende Parameter TYPE. Dieser hat die Syntax:

TYPE={MyISAM|BDB|InnoDB|Gemini}

Um nun die Vorteile von transaktionsfähigen Tabellen nutzen zu können, muss man eine Sequenz von SQL-Statements mit BEGIN einleiten und mit COMMIT beenden. COMMIT führt alle seit dem letzten BEGIN an die Datenbank abgesetzten Kommandos tatsächlich aus. Bis zu diesem Zeitpunkt kann man statt einer Ausführung der Statements mit COMMIT die Kommandosequenz auch mit ROLLBACK widerrufen.


4.1 Besonderheiten in BDB-Tabellen

BDB-Tabellen müssen stets einen Primärschlüssel besitzen. Legt man eine Tabelle ohne solchen an, wird von MySQL automatisch ein verborgener Primärschlüssel generiert. Der BDB-Tabellentreiber sperrt im Rahmen einer Transaktion zumindest alle Datensätze, die von der Transaktion in irgendeiner Weise verändert wurden.

4.2 Besonderheiten in InnoDB-Tabellen

Der InnoDB-Treiber orientiert sich hinsichtlich der Leistungsmerkmale möglichst nahe am Transaktions-mechanismus von Oracle. Prinzipiell kümmert sich der Tabellentreiber selbständig um alle benötigten Locking-Mechanismen, was darauf hinausläuft, dass alle im Rahmen einer Transaktion veränderten Datensätze bis zum Ende der Transaktion durch einen Executive Lock gesperrt werden.

Ein wesentlicher Unterschied zum Konzept der BDB-Tabellen ist jedoch, dass SELECT-Statements auf gesperrte Datzensätze trotz der Sperrung ausgeführt werden. Dabei werden allerdings potenzielle Änderungen an den Datensätzen durch alle noch offenen (also weder mit COMMIT noch mit ROLLBACK abgeschlossenen) Transaktionen auf den entsprechenden Daten ignoriert. Ein mögliches Resultat dieses. Verhaltens kann sein, dass SELECT-Statements unter diesen Bedingungen "veraltete" Daten liefern.

Das hier beschriebene Default-Verhalten lässt sich mit MySQL-spezifischen Erweiterungen ändern:

1.   SELECT ... FOR UPDATE: Sperrung einzelner Datensätze ohne tatsächliche Veränderung (Anwendungszweck: Daten sollen zunächst gelesen und danach geändert werden).
2. SELECT ... IN SHARE MODE: Das SELECT-Statement wartet auf Freigabe der Datensätze durch alle noch offenen Transaktionen, anschließend werden die selektierten Datensätze mit einem Shared Lock gesperrt (Anwendungszweck: Man möchte Datensätze selbst verändern, aber eine änderung durch konkurrierende Clients verhindern).

Generell wird der maximale Timeout durch die Variable innoDB lock wait timeout=n (mit n Zeit in Sekunden) gesteuert. Wird der Timeout erreicht, wird die betreffende Transaktion serverseitig mit ROLLBACK abgeschlossen.


5 Transaktionsunterstützung in Cold Fusion

Cold Fusion 5.0 ermöglicht es, SQL-Statements mit dem CFQUERY-Tag an auf dem Server eingebundene Datenbanken abzusetzen. Einige Datenbanken bzw. Datenbanktreiber ermöglichen auch das direkte Ausführen mehrerer, durch Semikolon getrennter, Statements im Rahmen einer Query. Diese Fähigkeit impliziert aber noch keine Transaktionseigenschaften.

Mit dem Tag CFTRANSACTION bietet Cold Fusion die Möglichkeit, Transaktionen von Seiten Cold Fusions einzuleiten und mit COMMIT oder ROLLBACK abzuschließen. Die Syntax des Tags sieht wie folgt aus:

<CFTRANSACTION action="begin|commit|rollback">
<!--- CFQUERY-Tags --->
</CFTRANSACTION>

Die möglichen Werte für den Action-Parameter sind hierbei Begin (Start der Transaktion, Default-Wert), Commit (bestätigt eine offene Transaktion) und Rollback (nimmt eine offene Transaktion zurück). Mit Hilfe des Isolation-Parameters, der oben nicht aufgeführt ist, lassen sich verschiedene Isolation-Levels für die Transaktion festlegen. Isolation-Levels werden sowohl von BDB-Tabellen als auch von InnoDB-Tabellen nicht unterstützt. Im Bereich von MySQL findet man nur mit dem Gemini-Tabellentyp Möglichkeiten, auf solche Features zuzugreifen (vgl. [3]), daher wird auf diesen Parameter im Rahmen dieses Artikels nicht weiter eingegangen. Weitere Informationen hierzu findet man beispielsweise in [1, S. 104/105].


6 Beispiele


6.1 Einfache Transaktion um mehrere CFQUERY-Tags

<CFTRANSACTION>
  <CFQUERY datasource="Sales">
    INSERT INTO tblSales (SaleAmount, SaleDate)
    VALUES (100,10/20/2001)
  </CFQUERY>
  <CFQUERY datasource="Sales" Name="GetSaleId">
    SELECT Max(SaleId) AS maxid FROM tblSales
  </CFQUERY>
  <CFOUTPUT query="GetSaleId">
    #GetSaleId.maxid#
  </CFOUTPUT>
</CFTRANSACTION>

Zunächst wird mit CFTRANSACTION die Transaktion eingeleitet, indem der Datenbank BEGIN übermittelt wird (die Default-Action des Tags ist BEGIN). In der Transaktion wird zunächst ein Datensatz in eine Tabelle eingefügt und in einem zweiten Statement der aktuelle Maximalwert der Spalte SaleId dieser Tabelle abgefragt. Durch die Einbettung beider Abfragen in eine Transaktion ist sichergestellt, dass tatsächlich der korrekte Wert im gegebenen Kontext selektiert wird, ohne dass vorher von einem anderen Client weitere, das Ergebnis verfälschende Datensätze eingefügt werden können. Das abschließende CFTRANSACTION sendet wiederum ein BEGIN an die Datenbank, welches von MySQL als COMMIT der alten und BEGIN einer neuen Transaktion interpretiert wird.


6.2 Transaktionsende abhängig von externen Ereignissen

<CFSET externalOK=0>

<CFTRANSACTION>
  <CFQUERY name="GetAll" datasource="TT">
    SELECT * FROM Kunde
  </CFQUERY>
  <CFQUERY name="InsNewKunde" datasource="TT">
    INSERT INTO Kunde
    VALUES (NULL, 'Arbohn', 'Arne')
  </CFQUERY>
  <CFQUERY name="UpdKunde" datasource="TT">
    UPDATE Kunde
    SET KundeName='Bose'
    WHERE KundeID=1
  </CFQUERY>
  <CFSWITCH expression="#externalOK#">
    <CFCASE value="0">
      <CFTRANSACTION action="rollback"/>
    </CFCASE>
    <CFCASE value="1">
      <CFTRANSACTION action="commit"/>
    </CFCASE>
  </CFSWITCH>
</CFTRANSACTION>

Im oben angegebenen Codeblock wird auf Basis der in Kapitel 4 erstellten Datenstruktur eine Serie von SQL-Statements in Abhängigkeit vom Zustand einer Variablen entweder mit COMMIT oder mit ROLLBACK beendet. Dabei beachte man die XML-Syntax in den schließenden Tags.


6.3 Transaktionen zum Zweck des Debuggings einer Serie von SQL-Statements

Oft möchte man Codefragmente debuggen, die nach einigen problemlosen SQL-Statements (auch INSERT, DELETE, UPDATE) an einer bestimmten Stelle scheitern und steht dann vor der Problematik gewisse Änderungen an der Datenbank rückgängig machen zu müssen. Auch hierfür bieten sich Transaktionen an.

<CFTRANSACTION>
  <CFQUERY name="GetAll" datasource="TT">
    SELECT * FROM Kunde
  </CFQUERY>
  <CFQUERY name="InsNewKunde" datasource="TT">
    INSERT INTO Kunde
    VALUES (NULL, 'Arbohn', 'Arne')
  </CFQUERY>
  <CFABORT>
</CFTRANSACTION>

Die beiden SQL-Statements werden ausgeführt, man kann eventuelle Auswirkungen - oder im Fall von dynamischen Queries deren konkrete Ausprägung durch bestimmte Systemzustände - überprüfen.

CFABORT bricht das Template ab, die Transaktion bekommt den Rollback-Status und alle vorherigen Statements werden rückgängig gemacht.


7 Benchmarks und verwendete Infrastruktur

Die hier dargestellten Techniken und Beispiele wurden auf einem System mit folgender Ausstattung erstellt und getestet:

  • Physikalische Maschine: Toshiba Satellite 1800-814, Pentium III 1 Ghz, 256 MB RAM
  • Betriebssystem: Windows XP Professional
  • Webserver: IIS 5.1
  • Cold Fusion Server: CF Enterprise Server 5.0 in einer Vollinstallation
  • Datenbank: MySQL 3.23.49 (mysqld-max-nt als verwendetes Binary)
  • ODBC-Treiber: MyODBC 2.50.39 (vorherige Versionen unterstützen keine Transaktionen über ODBC)
Um die Geschwindigkeit der Transaktionstabellen in der Zusammenarbeit mit MySQL zu untersuchen, wurden in Anlehnung an [1] Benchmarks unter den oben genannten Bedingungen ausgeführt. Die Tabellenstruktur wurde mit folgendem SQL-Statement erzeugt:

CREATE TABLE TTest{MyISAM|BDB|InnoDB}
  (a INT NOT NULL AUTO_INCREMENT,
  b DOUBLE,
  c VARCHAR(255),
  PRIMARY KEY (a))
  TYPE={MyISAM|BDB|InnoDB}

Im Rahmen einer Schleife wurden 100, 500, 1000, 5000 und 10000 zufällige Einträge in die Tabelle geschrieben und eine Zeitmessung vorgenommen, um festzustellen, wie lange Cold Fusion zur Abarbeitung der verschiedenen Szenarien benötigte. Dabei wurde einerseits der Zeitaufwand für das Abarbeiten des Templates mit Erzeugung der Daten und dem Schleifendurchlauf gemessen, andererseits die kumulierte Zeit, die für die Anfragen an die Datenbank aufgebracht wurde. Um Caching-Effekte möglichst auszuschalten, wurde der Parameter " Limit the maximum number of cached queries on the server to..." im Cold Fusion Administrator auf den Wert 0 gesetzt. Die Tabellen liegen in der MySQL-Datenquelle Test bereit.

Das Skript zur Bearbeitung der Testfälle sieht wie folgt aus:

<--- Anzahl Einzeltests pro Durchlauf --->
<CFSET Max=5>
<CFSET Commitschwelle=0.1>

<CFLOOP index="g" list="100,500,1000,5000,10000">
  <CFSET aTimeDB=ArrayNew(1)>
  <CFSET aTimeALL=ArrayNew(1)>
  <CFSET aCommitcounter=ArrayNew(1)>
  <CFOUTPUT>
<B>#g# Datensaetze:</B><BR><BR> </CFOUTPUT>
  <CFFLUSH>
  <CFLOOP index="h" from="1" to="#Max#">
    <CFSET TimeDB=0>
    <CFSET TimeALL=0>
    <CFSET TimestartALL=GetTickCount()>
    <CFSET Commitcounter=0>

    <!--- Fall A: Transaktionen um jeden Einzeldurchlauf --->
    <!--- <CFTRANSACTION> --->

    <CFLOOP index="i" from="1" to="#g#">
      <CFSET VarcharToInsert="">
      <CFLOOP index="j" from="1" to="10">
        <CFSET VarcharToInsert=VarcharToInsert & Chr(Int(RandRange(65,90)))>
      </CFLOOP>
      <CFSET DoubleToInsert=Rand()>
      <CFSET TimestartDB=GetTickCount()>

      <!--- Fall B: Transaktionen um jedes Query --->
      <!--- <CFTRANSACTION> --->

      <CFQUERY datasource="Test" name="Test">
        INSERT INTO TTest{MyISAM|BDB|InnoDB}
        VALUES (NULL, #DoubleToInsert#, '#VarcharToInsert#')
      </CFQUERY>

      <!--- Fall B: Transaktionen um jedes Query --->
      <!--- </CFTRANSACTION> --->

      <CFSET Zufallscommit=Rand()>
      <CFIF Zufallscommit lt Commitschwelle>
        <CFTRANSACTION action="COMMIT"/>
        <CFSET TimeendDB=GetTickCount()>
        <CFSET TimeDB=TimeDB+TimeendDB-TimestartDB>
        <CFSET Commitcounter=Commitcounter+1>
      <CFELSE>
        <CFSET TimeendDB=GetTickCount()>
        <CFSET TimeDB=TimeDB+TimeendDB-TimestartDB>
      </CFIF>
    </CFLOOP>

    <!--- Fall A: Transaktionen um jeden Einzeldurchlauf --->
    <!--- </CFTRANSACTION> --->

    <CFSET TimeendALL=GetTickCount()>
    <CFSET TimeALL=TimeendALL-TimestartALL>
    <CFSET aTimeDB[h]=TimeDB>
    <CFSET aTimeALL[h]=TimeALL>
    <CFSET aCommitcounter[h]=Commitcounter>
    <CFQUERY datasource="Test" name="Test">
      DELETE FROM TTest{MyISAM|BDB|InnoDB}
    </CFQUERY>
    <CFOUTPUT>
      Durchlauf #h#: DBTime: #aTimeDB[h]# --- AllTime:
      #aTimeALL[h]# --- Commits: #aCommitcounter[h]#<BR>
    </CFOUTPUT>
    <CFFLUSH>
  </CFLOOP>
  <CFOUTPUT>
    Durchschnitt DBTime: #ArrayAvg(aTimeDB)# --- Durchschnitt
    AllTime: #ArrayAvg(aTimeALL)# --- Durchschnitt Commits:
    #ArrayAvg(aCommitcounter)#<BR>
  </CFOUTPUT>
  <BR>
  <CFFLUSH>
</CFLOOP>

In den folgenden Tabellen werden die Ergebnisse der Benchmarks dargestellt.


7.1 MyISAM

Der MyISAM-Tabellentreiber unterstützt keine Transaktionen. Um festzustellen, wie stark der Einfluss der Debug-Optionen des Cold Fusion Servers auf den Benchmark ist, wurde der Test bei diesem Tabellentyp jeweils einmal mit ein- bzw. ausgeschaltetem serverseitigen Debugging durchgeführt. Man erkennt,

Anzahl Sätze mit Debugging ohne Debugging
  TimeDB[s] TimeALL[s] TimeDB[s] TimeALL[s]
100 0,1862 0,2864 0,2504 0,3506
500 0,8612 1,326 0,8336 1,2818
1000 1,5964 2,6316 1,6564 2,5558
5000 8,5518 13,171 7,8056 12,7224
10000 16,6692 26,544 15,7702 25,8904

dass der Einfluss der Debugging-Option vernachlässigbar scheint. Es ist eine Tendenz zur Verschlechterung der Ergebnisse bei sehr vielen Datensätzen erkennbar; an dieser Stelle müsste man gegebenenfalls noch weitere Untersuchungen durchführen. Weiterhin sieht man, dass die Datenbank im hier getesteten Bereich linear skaliert.


7.2 BDB

Mit dem BDB-Treiber wurden drei verschiedene Untersuchungen durchfgeführt. Zum einen wurde gegenüber dem MyISAM-Benchmark nur der Tabellentyp geändert, also ohne expliziete Transaktionen gearbeitet. Desweiteren wurde eine Transaktion um jeden Einzeldurchlauf des Tests gelegt, so dass jeweils 100, 500, und 1000 Statements innerhalb einer Transaktion abgesetzt wurden (Fall A) und abschließend im Fall B um jedes Statement eine eigene Transaktion gelegt.

Anzahl Sätze ohne TA TA zusammen
  TimeDB[s] TimeALL[s] TimeDB[s] TimeALL[s]
100 4,5688 4,6748 0,2448 0,393
500 21,4314 21,940 0,8136 1,472
1000 35,4826 36,4768 1,6426 2,8142

Anzahl Sätze TA
  TimeDB[s] TimeALL[s]
100 4,1366 4,234
500 19,8726 20,3372
1000 42,6746 43,7264

Auf die Durchführung der Tests mit 5000 und 10000 Statements wurde aus Gründen der Laufzeit verzichtet. Die Ergebnisse zeigen auf, dass sich die BDB-Tabellen im Fall A nahezu in der gleichen Geschwindigkeit wie die MyISAM-Tabellen verwenden lassen. Das war auch zu erwarten, da der entstehende Transaktionsoverhead je Einzeldurchlauf nur einmal auftritt. Im Fall B ist die Performance allerdings um den Faktor 25 schlechter als in Fall A. Auch eine solche Tendenz ist zu erwarten, da nun jedes einzelne Statement mit einer Transaktion umgeben wird, die entsprechend vom Datenbankserver gelockt und verwaltet werden muss. Der sehr hohe Faktor kann sicherlich auch von Eigenschaften der zugrundeliegenden Hardware herrühren. Gleiches trifft auch für die Situation ohne Transaktionen zu, da sich MySQL im sog. Auto-Commit-Modus befindet und nach jedem Statement ein BEGIN an den Tabellentreiber sendet.


7.3 InnoDB

Für den InnoDB-Treiber gelten hinsichtlich der Testausführung alle Anmerkungen zum BDB-Treiber. Auch hier beobachtet man sehr gute Zeiten bei der Schachtelung einer einzigen Transaktion um jeden Einzeldurchlauf des Tests, sehr schlechte Zeiten bei der Schachtelung jedes Statements in eine eigene Transaktion.

Anzahl Sätze ohne TA TA zusammen
  TimeDB[s] TimeALL[s] TimeDB[s] TimeALL[s]
100 4,8426 4,9488 0,2324 0,4266
500 22,4186 22,929 22,929 1,434
1000 45,6798 46,6312 1,9886 3,0646

Anzahl Sätze TA
  TimeDB[s] TimeALL[s]
100 4,1696 4,296
500 23,5216 24,0244
1000 46,0038 47,0818

Da die InnoDB-Tabellen die nutzbringendste Form der neuen MySQL-Tabellentypen darzustellen scheinen, wurde mit diesem Tabellentyp noch ein weiterer Test durchgeführt, der eine realistischere Last auf die Datenbank simulieren soll. Dazu bestanden nach jedem einzelnen Query Chancen von 0%, 2%, 5%, 10%, 20%, 33% sowie 50% auf die Absetzung eines Zwischen-Commits, so dass Transaktionsketten entstehen sollten, wie sie auch möglicherweise im Realbetrieb zu erwarten sind. Die Ergebnisse entsprechen im wesentlichen den Erwartungen nach den bereits durchgeführten Tests. Je höher die vorgegebene Commit-Wahrscheinlichkeit ist, desto niedriger die Performance der Datenbank; es läßt sich sogar eine annähernd lineare Skalierung der Ergebnisse im Vergleich zu den Benchmarks der Fälle A und B aus dem InnoDB-Abschnitt erkennen.

Commit-W'keit 100 Datensätze 500 Datensätze
  TimeDB[s] TimeALL[s] TimeDB[s] TimeALL[s]
0% 0,247 0,452 1,0174 1,6382
2% 0,3748 0,5008 1,6764 2,1912
5% 0,3584 0,5164 2,1352 2,692
10% 0,7788 0,9296 5,5238 6,0894
20% 1,6324 1,7524 5,74 6,2052
33% 1,7644 1,9346 8,4502 8,9228
50% 2,7 2,84 13,2494 13,7318


8 Mögliche Probleme und nicht behandelte Themen

  • Dynamischer Wechsel des Tabellentypen bei bereits bestehenden Tabellen
  • Mögliche Einschränkungen bei der Nutzung bestimmter Tabellentypen
    • InnoDB: Text- oder Blob-Spalten haben Probleme mit Schlüsseln und Indizes
    • BDB und InnoDB: SHOW TABLE STATUS liefert keine zuverlässigen Werte, eine Benutzung des Tools MySQLFront wird damit an manchen Stellen eingeschränkt
  • Umsetzung des hier Gezeigten auf andere Plattformen (HP-UX, Linux, Solaris)
  • Erweiterung der Benchmarks auf praxisorientiertere Szenarien (Mischung aus SELECT-, UPDATE-, INSERT- und DELETE-Statements, Verwendung von DBMS-Verwaltungstools zum Vergleich der Zugriffsgeschwindigkeiten)
  • Untersuchung der Gemini-Tabellen, die hier leider nicht vorlagen

9 Fazit

Im Rahmen dieses Artikels wurden grundlegende Eigenschaften und Features der neuen, transaktionsfähigen Tabellentypen in MySQL vorgestellt. Besonders wurde dabei auf die Zusammenarbeit dieser Mechanismen mit dem Applikationsserver Cold Fusion 5.0 eingegangen und im Rahmen von einfachen Bench-marks gezeigt, unter welchen Bedingungen die Tabellentypen MyISAM, BDB und InnoDB hinsichtlich Performance und Leistungsfähigkeit einsetzbar sind.

Im Ramen der Untersuchung wurde festgestellt, dass die InnoDB-Tabellen für die Anwendung in Web-Applikationen unter den Gesichtspunkten Performance und Leistungsfähigkeit zu bevorzugen sind, wenn die Applikation (zumindest teilweise) Transaktionssicherheit erfordert. Der Komfort und die Sicherheit der Nutzung solcher Tabellen bringt unweigerlich Einbußen im Bereich der Performance mit sich. Dabei ist das Maß an Geschwindigkeitsverlust letztlich aber von der Länge der einzelnen Transaktionsketten abhängig. Hierbei ist eine genau Planung vonnöten, um sich bei der Entwicklung der Applikation nicht selbst eine Performance-Falle zu stellen.

Literatur

1.   Koffler, M., "Ganz oder gar nicht - Transaktionen in MySQL", in: Linux-Magazin 08/2001, Linux-New-Media Verlag, 2001
2.   MySQL Online Documentation: http://www.mysql.com/doc/
3.   Nusphere: Gemini-Tabellen: http://www.nusphere.com

Download des gesamten Artikels als PDF



Kai König koenig@msg-at.net - 21.06.2002

Zurück


Das deutsche ColdFusion-Forum cfml.de ist das Portal für Einsteiger und Experten zum Thema ColdFusion und der ColdFusion Markup Language (CFML).

© 2017 Webdesign & Hosting: CHC ONLINE Kassel | SOLVA Content-Management-System CMS
Urlaub-Angebote.de - Urlaub mit Bestpreis-Garantie buchen