Ulf Wendel

DYNAMIC tauscht Speicherplatz gegen Geschwindigkeit

MaxDB führt zur Laufzeit allerlei Ausgleichsoperationen auf dem Speichermedium aus, um eine möglichst platzsparende Datenablage zu erreichen und gleichbleibende Geschwindigkeit zu erreichen. Den MaxDB-Anwendern ist die als Reorganisationsfreiheit bekannt. Doch wie im Blogeintrag “MaxDB’s Reorganisationsfreiheit” bereits erwähnt, kann man MaxDB anweisen, nicht alle Ausgleichsoperationen durchzuführen.

Bringt es etwas?

Ich habe mir heute ein kleines Programm geschrieben, daß einige, einfache Operationen durchführt um den Einfluß von DYNAMIC zu bewerten. DYNAMIC ist ein Attribut, welches bei der Tabellendefinition angegeben werden kann. Es bewirkt, daß MaxDB nur noch vereinzelt Ausgleichsoperationen durchführt. Dies beschleunigt Änderungsoperationen führt jedoch zu einem erhöhten Speicherbedarf.

Leider habe ich keine Angaben darüber gefunden, wie groß der Effekt von DYNAMIC ausfällt. Deshalb habe ich selbst ein kleines Testprogramm geschrieben und nachgemessen. Ich habe mir keine besondere Mühe gemacht einen aussagekräftigen Benchmark zu entwickeln. Die Messergebnisse, die weiter unten aufgeführt werden, sollten nur als grobe Anhaltspunkte verstanden werden. Sie erheben keinen Anspruch in irgendeiner Weise sinnvolle Rückschlüsse auf reale Applikationen zu geben. Die Charakteristika einer Applikation stimmen in den seltensten Fällen mit denen einer Benchmark Suite überein. Eigene Test mit er eigenen Applikation sind deshalb unverzichtbar.

Tabellendefinition

Für den Test wurde eine einfache Tabelle mit einem Integer-Primärschlüssel und einigen Varchar-Spalten verwendet. Varchar wurde benutzt, um MaxDB zu zwingen bei Längenänderungen Ausgleichsoperationen auszuführen. Im Normalbetrieb führt eine Längenänderung zum Verschieben von Datensätzen auf einer Datenseite und zur Aktualisierung der Positionsliste, siehe “MaxDB’s Reorganisationsfreiheit”.

CREATE TABLE DYNAMIC_TEST (
    pk INTEGER,
    a VARCHAR(100),
    b VARCHAR(100),
    c VARCHAR(100),
    d VARCHAR(100),
    e TIMESTAMP,
    PRIMARY KEY (pk)
  ) DYNAMIC

CREATE TABLE STATIC_TEST (
    pk INTEGER,
    a VARCHAR(100),
    b VARCHAR(100),
    c VARCHAR(100),
    d VARCHAR(100),
    e TIMESTAMP,
    PRIMARY KEY (pk)
  )

Alle Tests, die ausgeführt werden, werden auf der gezeigten Tabelle DYNAMIC_TEST und einer Tabelle STATIC_TEST durchgeführt. Die Tabelle STATIC_TEST unterscheidet sich nur durch das Fehlen des Tabellenattribut DYNAMIC von der Tabelle DYNAMIC_TEST

Alle Messungen laufen praktisch vollständig im Hauptspeicher ab. Der I/O-Buffer ist mit einem CACHE_SIZE Wert von 60,000 Datenseiten a 8kb großzügig bemessen. Die maximale Tabellengröße liegt während des Tests bei jeweils rund 4.600 Datenseiten. Zusammen belegen sie also weniger als 10.000 Datenseiten, was nicht einmal 20% des I/O-Buffer beträgt. Die Testmaschine hat 1.5GB platz und kann zusätzlich zum I/O-Buffer der Datenbank etliche Daten im Betriebssystem Cache halten. Das Tool iostat zeigt während des gut 10 Minuten andauernden Testlaufs eine I/O-Wait Rate von weniger als 1% im 5-Minuten Mittel.

Getestet wurde mit MaxDB 7.5.00.26 unter Suse 9.3.

Testverfahren

Zu Beginn des Tests werden beide Tabellen neu angelegt und mit 100.000 Datensätzen befüllt. Die Tabellen werden mit identischen Daten versorgt. Die Spalten a, b, c und d werden mit zufälligen, 50-100 Zeichen langen Strings belegt. Nach jeder großen Änderungsoperation, nach jedem Einzeltest werden die Tabellenstatistiken aus der Systemtabelle TABLESTATISTICS abgelegt. Die erste Erfassung der Statistiken erfolgt nach der initialen Befüllung und wird in den Testergebnissen als “Ausgangslage” bezeichnet.

Im Testabschnitt “UPDATE 1” werden 100.000 UPDATE-Anweisungen auf den Tabellen ausgeführt. Es werden hierfür zufällige Datensätze ausgewählt und aktualisiert. Die verwendete UPDATE-Anweisung ist: UPDATE [DYNAMIC_TEST|STATIC_TEST] SET a = [Zufallswert, 0-100 Zeichen], d = [Zufallswert, 0-100 Zeichen] WHERE pk = [Zufallswert]. Wie bei der Anlage der Daten werden die generierten UPDATE-Anweisungen in beiden Tabellen ausgeführt, d.h. es bleibt bei einem identischen Datenbestand in den Tabellen.

Nach der zufälligen Aktualisierung erfolgt eine sequentielle Aktualisierung aller Datensätze in beiden Tabellen. Die Aktualisierung erfolgt in Primärschlüsselreihenfolge. Es wird folgende Anweisung ausgeführt: UPDATE [DYNAMIC_TEST|STATIC_TEST] SET b = '', c = 'abc' WHERE pk = [aufsteigender Schlüsselwert] . Dieser Schritt wird als “UPDATE 2” bezeichnet.

Nachdem mit insgesamt 200.000 Anweisungen jeder Datensatz in den Tabellen zwei mal verändert wurde, wird die Geschwindigkeit beim wahlfreien Zugriff über den Primärschlüssel gemessen. Erstmals werden nicht identische Zugriffe ausgeführt sondern für jede Tabelle 100.000 zufällige Primärschlüssel ermittelt. Durch die Menge sollte sich jedoch ein ähnliches, d.h. gleich zufälliges Zugriffsmuster ergeben. Im Mittel wird jeder Datensatz einmal abgefragt. Die Ergebnisse dieses Tests werden in der Auswertung unter “Random SELECT” angezeigt.

Der Effekt von Löschungen wird im Schritt “DELETE” vermessen. Insgesamt werden 20.000 Datensätze in aufsteigender Primärschlüsselreihenfolge gelöscht. Die Anzahl der Datensätze pro Datenseite schwankte nach der initialen Befüllung zwischen 10 und 25, nach dem Schritt “UPDATE 2” erhöht sich dieser Wert auf 20 bis 40 Datensätze pro Datenseite. Eine Löschung jedes 5. Datensatz dürfte damit jeden 4. bis 8. Datensatz pro Datenseite treffen. Der bereits vor der Löschung auf rund 50% gesunkene Belegungsgrad in STATIC_TABLE wird unter einen Schwellenwert fallen und viele Ausgleichsoperationen nach sich führen.

Im letzten Test “INSERT” werden die soebend gelöschten Primärschlüsselwerte wieder eingefügt. In jede Tabelle werden also 20.000 neue Datensätze eingefügt:

INSERT INTO [DYNAMIC_TEST|STATIC_TEST] (pk, a, b) 
  VALUES ([Primärschlüssel], 
  'abcdefghijklmdefghijklmdefghijklmdefghijklmdefghijklmdefghijklmdefghijklm', 
  'defghijklmdefghijklmdefghijklmdefghijklmdefghijklmdefghijklmdefghijklm')

.

Testergebnisse: Performanz

Die mit dem Attribut DYNAMIC definierte Tabelle DYNAMIC_TEST kann leichte Geschwindigkeitsvorteile von rund 10% bei Löschoperationen und spürbare 20% beim abschließenden INSERT-Test verbuchen. Fast keine Unterschiede sind bei der sequentiellen Aktualisierung “UPDATE 2” zu erkennen. Auch der minimale Vorteil beim “Random SELECT” ist nicht nennenswert. Bei mehreren Messungen schwankten alle relativen Prozentwerte zwischen STATIC_TEST (mit Reorganisation zur Laufzeit) und DYNAMIC_TEST (minimale Reorganisation) im Bereich von 2-5%. Damit läßt sich nur für DELETE- und INSERT-Anweisungen ein Trend feststellen.

   STATIC_TEST  DYNAMIC_TEST  
UPDATE 2 67.46 s 68.53 s 101 %
Random SELECT 78.62 s 77.11 s 98 %
DELETE 15.04 s 13.66 s 90 %
INSERT 12.65 s 10.01 s 79 %

Die Geschwindigkeitsvorteile werden jedoch mit einem erhebliche höheren Speicherplatzbedarf erkauft. Die mit dem Attribut DYNAMIC versehene Tabelle sinkt am Ende des Test auf eine mittlere Belegung der Datenseiten von nur 45%, während die normale Tabelle einen guten Füllgrad von 85% erreicht. In absoluten Zahlen ausgedrückt belegt die Tabelle DYNAMIC_TEST 87% mehr Speicherplatz.

Fazit

Wenn Sie viel Speicherplatz zur Verfügung haben, ihre Datenbank weitgehend aus dem I/O-Buffer bedient werden kann und ihre Anwendung eine große Menge von Lösch- und Einfügeoperationen (DELETE, INSERT) hat, dann ist DYNAMIC interessant für Sie. Entsteht die Last vorwiegend durch Aktualisierungen (UPDATE), dann sind wahrscheinlich nur geringe Geschwindigkeitsvorteile zu erwarten. Sollte es nicht möglich sein alle Daten im I/O-Buffer zu halten, dann besteht die Gefahr daß das Lesen der Datenseiten von der Platte zum dominierenden Faktor wird. DYNAMIC kann zu einem sehr schlechten Belegungsgrad der Datenseiten führen und weit mehr langsame I/O-Operationen zum Lesen der gleichen Menge von Datensätzen hervorrufen als eine reorganisierte Tabelle.

Wie vorsichtig man mit diesen Beobachtungen umgehen muß, zeigte ein kleiner Dreh an den Parametern für den DELETE und INSERT Test. Löscht man jede 1. Zeile, also alles und füllt alles wieder auf, dann ist DYNAMIC nicht mehr schneller und fällt negativ auf mit einer nur 20%-igen Belegung der Datenseiten.

Es ist also dringend anzuraten Tests mit der eigenen Applikation durchzuführen.

Testergebnisse: Speicherplatzbelegung

Ausgangslage

   STATIC_TEST  DYNAMIC_TEST
Root pno 15668 105677 674 %
Filetype perm perm 0 %
Used pages 4618 4618 100 %
Index pages 14 14 100 %
Leaf pages 4604 4604 100 %
Index levels 2 2 100 %
Space used in all pages (%) 91 91 100 %
Space used in root page (%) 3 3 100 %
Space used in index pages (%) 87 87 100 %
Space used in index pages (%) min 3 3 100 %
Space used in index pages (%) max 99 99 100 %
Space used in leaf pages (%) 91 91 100 %
Space used in leaf pages (%) min 38 38 100 %
Space used in leaf pages (%) max 95 95 100 %
Rows 100000 100000 100 %
Avg rows per page 21 21 100 %
Min rows per page 9 9 100 %
Max rows per page 23 23 100 %
Avg row length 339 339 100 %
Min row length 246 246 100 %
Max row length 436 436 100 %
Avg key length 4 4 100 %
Min key length 2 2 100 %
Max key length 5 5 100 %
Avg separator length 4 4 100 %
Min separator length 3 3 100 %
Max separator length 5 5 100 %
Defined LONG columns 0 0 0 %
Avg LONG column length 0 0 0 %
Min LONG column length 0 0 0 %
Max LONG column length 0 0 0 %
LONG column pages 0 0 0 %
Avg pages per LONG column 0 0 0 %
Min pages per LONG column 0 0 0 %
Max pages per LONG column 0 0 0 %

UPDATE 1

   STATIC_TEST  DYNAMIC_TEST
Root pno 15668 105677 674 %
Filetype perm perm 0 %
Used pages 4618 4618 100 %
Index pages 14 14 100 %
Leaf pages 4604 4604 100 %
Index levels 2 2 100 %
Space used in all pages (%) 83 83 100 %
Space used in root page (%) 3 3 100 %
Space used in index pages (%) 87 87 100 %
Space used in index pages (%) min 3 3 100 %
Space used in index pages (%) max 99 99 100 %
Space used in leaf pages (%) 83 83 100 %
Space used in leaf pages (%) min 58 36 62 %
Space used in leaf pages (%) max 93 93 100 %
Rows 100000 100000 100 %
Avg rows per page 21 21 100 %
Min rows per page 15 9 60 %
Max rows per page 23 23 100 %
Avg row length 307 307 100 %
Min row length 147 147 100 %
Max row length 437 437 100 %
Avg key length 4 4 100 %
Min key length 2 2 100 %
Max key length 5 5 100 %
Avg separator length 4 4 100 %
Min separator length 3 3 100 %
Max separator length 5 5 100 %
Defined LONG columns 0 0 0 %
Avg LONG column length 0 0 0 %
Min LONG column length 0 0 0 %
Max LONG column length 0 0 0 %
LONG column pages 0 0 0 %
Avg pages per LONG column 0 0 0 %
Min pages per LONG column 0 0 0 %
Max pages per LONG column 0 0 0 %

UPDATE 2

   STATIC_TEST  DYNAMIC_TEST
Root pno 15668 105677 674 %
Filetype perm perm 0 %
Used pages 3451 4618 133 %
Index pages 13 14 107 %
Leaf pages 3438 4604 133 %
Index levels 2 2 100 %
Space used in all pages (%) 59 44 74 %
Space used in root page (%) 3 3 100 %
Space used in index pages (%) 70 87 124 %
Space used in index pages (%) min 3 3 100 %
Space used in index pages (%) max 97 99 102 %
Space used in leaf pages (%) 59 44 74 %
Space used in leaf pages (%) min 50 20 40 %
Space used in leaf pages (%) max 78 52 66 %
Rows 100000 100000 100 %
Avg rows per page 29 21 72 %
Min rows per page 21 9 42 %
Max rows per page 44 23 52 %
Avg row length 161 161 99 %
Min row length 44 44 100 %
Max row length 245 245 100 %
Avg key length 4 4 100 %
Min key length 2 2 100 %
Max key length 5 5 100 %
Avg separator length 4 4 100 %
Min separator length 3 3 100 %
Max separator length 5 5 100 %
Defined LONG columns 0 0 0 %
Avg LONG column length 0 0 0 %
Min LONG column length 0 0 0 %
Max LONG column length 0 0 0 %
LONG column pages 0 0 0 %
Avg pages per LONG column 0 0 0 %
Min pages per LONG column 0 0 0 %
Max pages per LONG column 0 0 0 %

DELETE

   STATIC_TEST  DYNAMIC_TEST
Root pno 15668 105677 674 %
Filetype perm perm 0 %
Used pages 2463 4618 187 %
Index pages 13 14 107 %
Leaf pages 2450 4604 187 %
Index levels 2 2 100 %
Space used in all pages (%) 66 35 53 %
Space used in root page (%) 3 3 100 %
Space used in index pages (%) 50 87 174 %
Space used in index pages (%) min 3 3 100 %
Space used in index pages (%) max 69 99 143 %
Space used in leaf pages (%) 66 35 53 %
Space used in leaf pages (%) min 50 17 34 %
Space used in leaf pages (%) max 92 44 47 %
Rows 80000 80000 100 %
Avg rows per page 32 17 53 %
Min rows per page 22 8 36 %
Max rows per page 48 19 39 %
Avg row length 161 161 99 %
Min row length 45 45 100 %
Max row length 245 245 100 %
Avg key length 4 4 100 %
Min key length 3 3 100 %
Max key length 5 5 100 %
Avg separator length 4 4 100 %
Min separator length 3 3 100 %
Max separator length 5 5 100 %
Defined LONG columns 0 0 0 %
Avg LONG column length 0 0 0 %
Min LONG column length 0 0 0 %
Max LONG column length 0 0 0 %
LONG column pages 0 0 0 %
Avg pages per LONG column 0 0 0 %
Min pages per LONG column 0 0 0 %
Max pages per LONG column 0 0 0 %

INSERT

   STATIC_TEST  DYNAMIC_TEST
Root pno 15668 105677 674 %
Filetype perm perm 0 %
Used pages 2465 4618 187 %
Index pages 13 14 107 %
Leaf pages 2452 4604 187 %
Index levels 2 2 100 %
Space used in all pages (%) 85 45 52 %
Space used in root page (%) 3 3 100 %
Space used in index pages (%) 50 87 174 %
Space used in index pages (%) min 3 3 100 %
Space used in index pages (%) max 69 99 143 %
Space used in leaf pages (%) 85 45 52 %
Space used in leaf pages (%) min 48 20 41 %
Space used in leaf pages (%) max 100 54 54 %
Rows 100000 100000 100 %
Avg rows per page 40 21 52 %
Min rows per page 23 9 39 %
Max rows per page 52 23 44 %
Avg row length 166 166 100 %
Min row length 45 45 100 %
Max row length 245 245 100 %
Avg key length 4 4 100 %
Min key length 2 2 100 %
Max key length 5 5 100 %
Avg separator length 4 4 100 %
Min separator length 3 3 100 %
Max separator length 5 5 100 %
Defined LONG columns 0 0 0 %
Avg LONG column length 0 0 0 %
Min LONG column length 0 0 0 %
Max LONG column length 0 0 0 %
LONG column pages 0 0 0 %
Avg pages per LONG column 0 0 0 %
Min pages per LONG column 0 0 0 %
Max pages per LONG column 0 0 0 %

Comments are closed.