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
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
Download des gesamten Artikels als PDF
Kai König koenig@msg-at.net - 21.06.2002