LOB Komprimierung mit Oracle 11g Einführung

Werbung
LOB Komprimierung mit Oracle 11g
Mathias Zarick . Consultant . Oktober 2009
Mit Oracle Database 11g ist es möglich, Large Objects (LOBs) komprimiert in der Datenbank
zu speichern. Durch dieses Feature aus der neuen kostenpflichtigen Advanced Compression
Option ist es möglich Speicherplatz zu sparen. Lohnt sich der Aufwand? Was bedeutet das für
die Application Performance? Dieser Artikel beleuchtet diese Fragen.
Einführung
Oracle hat die Implementierung der Large Objects (LOBs) in der Datenbank grundlegend
überarbeitet. Oracle verspricht mit dieser neuen Implementierung verbesserte Performance und
Verwaltung. Diese neuen LOBs sind ein weiteres Beispiel für die effektive Nutzung der
Architektur von lokalen Tablespaces mit Automatic Segment Space Management (ASSM). ASSM
Tablespaces sind daher auch eine Voraussetzug für das Anlegen dieser neuartigen LOBs, die
Oracle SecureFiles nennt.
SecureFiles
Die Nutzung von Oracle SecureFiles ist transparent für Anwendungen und APIs, die auf diese
LOBs zugreifen. Jegliche LOB Schnittstellen arbeiten wie auf den herkömmlichen LOBs, die es
natürlich auch noch gibt und jetzt BasicFiles heißen. Sowohl für BasicFiles als auch für
SecureFiles werden die drei Datentypen CLOB, NCLOB und BLOB unterstützt.
Dennoch gibt es auch Einschränkungen: Der LogMiner versteht SecureFiles mit 11gR1 noch
nicht, daher sind sie auf diesem Release nicht in Umgebungen mit Logical Standby Database
oder Streams einsetzbar. Diese Einschränkung fällt mit 11gR2, ab diesem Release kann der
LogMiner mit SecureFiles umgehen.
Oracle SecureFiles können im Gegensatz zu BasicFiles komprimiert, dedupliziert oder
verschlüsselt werden. Diese drei Technologien können orthogonal zueinander Anwendung
finden, d.h. keines der Features schließt ein anderes aus. Komprimierung und Deduplizierung
werden in diesem Artikel näher beleuchtet. Die Verschlüsselung, welche den SecureFiles wohl
den Namen gab, ermöglicht es, die LOBs basierend auf Transparent Data Encryption (TDE) zu
verschlüsseln.
SecureFiles bieten außerdem eine zusätzliche Logging Option FILESYSTEM_LIKE_LOGGING
mit welcher es nun möglich ist, Redo Informationen für Metadaten zu loggen, für Daten jedoch
nicht.
Nötige Lizenzierungen
Für die Verwendung von SecureFiles ohne Komprimierung, Deduplizierung oder
Verschlüsselung ist keine weitere Lizenz nötig. Sie sind sowohl in Standard Edition als auch in
Enterprise Edition verfügbar. Sobald jedoch eines der drei erwähnten Features verwendet wird,
ist die Enterprise Edition mit einer dazugehörigen Option notwendig. Für Komprimierung und
Deduplizierung ist das die Advanced Compression Option und für die Verschlüsselung die
Advanced Security Option. Bei einer kombinierten Anwendung werden entsprechend beide
Optionen fällig.
www.trivadis.com
Seite 1 / 15
Speicherung von LOBs
Um ein LOB zu speichern, verwendet Oracle auch für SecureFiles die gleichen
Datenstrukturen, ein LOB Segment und einen LOB Index. Der LOB Index wird benötigt, um auf
LOB Chunks (Erklärung folgt unten) aus dem LOB Segment zuzugreifen. LOBs können nach wie
vor inline (enable storage in row) oder auch out-of-line (disable storage in row) gespeichert
werden. Für LOBs, die out-of-line gespeichert werden, speichert Oracle einen LOB Locator in
der entsprechenden Row. Der LOB Locator bietet dann den Einstieg, um über den LOB Index
auf das LOB im LOB Segment zuzugreifen. Wird hingegen Inline Speicherung verwendet, so
können kleine LOBs mit in der Row also zusammen mit den anderen Spalten der Tabelle in
demselben Block gespeichert werden. Überschreitet das LOB jedoch eine Größe von ca. 4000
Bytes wird es immer komplett out-of-line gespeichert. Inline Speicherung empfiehlt sich nur für
kleine LOBs, die häufig zusammen mit den anderen Spalten der Tabelle gelesen werden. Gibt
es hingegen viele Full Table Scans auf der Tabelle, die die LOB Daten nicht brauchen, so
sollten sie unbedingt out-of-line gespeichert werden, um nicht ständig über unnötige Daten
hinweglesen zu müssen. Der Default ist nach wie vor „enable storage in row“.
Die Daten in den LOB Segmenten werden in Chunks unterteilt. Sie bilden eine kleinste Einheit
für den Zugriff und die Manipulation und müssen ein Vielfaches der Blocksize sein. Bei
BasicFiles können sie maximal 32K groß sein und sind immer gleich groß. Hier wird es mit
Oracle 11g spannend. Mit dem Zeitalter der SecureFiles sind diese Chunkgrößen nämlich
dynamisch und können auch weitaus größer als nur 32K werden. Der Parameter Chunk ist
jedoch nach wie vor auch für SecureFiles gültig, er dient jedoch nur noch der
Abwärtskompatibilität bzw. wird vom Oracle Server als Vorschlag erachtet.
Lesekonsistenz
Bezüglich Lesekonsistenz gibt es auch eine Neuerung im Vergleich zu BasicFiles. Der
PCTVersion Parameter, mit welchem es möglich war, eine Prozentzahl des Platzes des LOB
Segmentes für alte LOB Versionen anzugeben, ist für SecureFiles nicht mehr gültig1. Hier
kommt nur noch der Retention Parameter zum Einsatz. Bei diesem besseren Ansatz wird nicht
ein Prozentsatz sondern eine Zeitperiode definiert. Und dieser Parameter wird mit den
SecureFiles noch erweitert. Man kann neben dem Default AUTO, welches nur konsistentes
Lesen sicherstellt, auch MIN plus eine Zeitspanne in Sekunden angeben. Ein weiterer Wert für
Retention ist MAX. Alte LOB Versionen werden dann bis zu einer anzugebenen MAXSIZE
(Größe des Segments) gespeichert. Sind alle aktuellen Versionen der LOBs jedoch größer als
diese MAXSIZE wird keine alte Version mehr im Segment gespeichert. Keine alten Versionen
kann man ebenso mit der Einstellung NONE für Retention erreichen.
Caching
Beim Caching gibt es nichts Neues. Der Default ist nach wie vor NOCACHE, d.h. auf ein LOB
wird im Normalfall immer über direct physical reads bzw. writes zugegriffen, und es wird nicht
im Buffer Cache abgelegt. CACHE READS ist eine Option, die es erlaubt die Blöcke des LOBs
nur für das Lesen zu cachen, nicht für das Schreiben und CACHE cached die Blöcke
letztendlich in beiden Fällen.
Migration
Um Daten
Methoden.
möchte ich
export und
1
von BasicFiles zu SecureFiles zu migrieren, gibt es leider keine „einfachen“
Die Daten müssen wirklich bewegt werden. Als Möglichkeiten zur Migration
„Create table … as select …“, „insert into … select …“, „alter table … move lob“,
import, Data Pump und Online Table Redefinition mittels DBMS_REDEFINITION
Versucht man ein LOB als SecureFile mit dem PCTVersion Parameter anzulegen, so bekommt man
einen Fehler ORA-22853: invalid LOB storage option specification.
www.trivadis.com
Seite 2 / 15
nennen. Die letztgenannte ist die einzige, die es ermöglicht online Migrationen durchzuführen,
ohne zugreifende Applikationen zu behindern.
Syntax und init.ora Parameter
Die Syntax für die Anlage eines SecureFiles, ist hier schematisch dargestellt:
CREATE TABLE <TABELLE>
( <SPALTEN>,
<LOBSPALTE> BLOB,
...
)
<STORAGE KLAUSEL FUER TABELLENSEGMENT>
LOB (<LOBSPALTE>) STORE AS SECUREFILE <LOBSEGMENTNAME> (
TABLESPACE <TABLESPACENAME>
DISABLE STORAGE IN ROW
<STORAGE KLAUSEL FUER LOBSEGMENT>
)
;
Konkrete Beispiele werden im Laufe des Artikels folgen. Die vollständige Syntaxbeschreibung
finden Sie in der Oracle Dokumentation.
Sollten Sie keinen Zugriff auf die SQL Anweisungen haben, welche die Tabellen erstellen und
die Speicherungsmethode nicht nachträglich mühsam ändern wollen, dann sind vielleicht
folgende Parameter – welche Sie auch auf Session Ebene ändern können – interessant:
Name
DB_SECUREFILE
_KDLXP_LOBCOMPRESS
_KDLXP_LOBDEDUPLICATE
Bedeutung
NEVER
bedeutet,
dass
SecureFiles
mit
Fehler
verweigert werden.
PERMITTED bedeutet, dass
SecureFiles angelegt werden
können, es muss aber auch so
spezifiziert werden.
Bei ALWAYS werden wenn
möglich immer SecureFiles
angelegt.
Bei
IGNORE
werden
SecureFiles immer ignoriert
und BasicFiles angelegt.
Wenn
TRUE
wird
ein
SecureFile
immer
komprimiert
(medium
Kompression) unabhängig der
Spezifikation.
Wenn
TRUE
wird
ein
SecureFile immer dedupliziert
angelegt unabhängig der
Spezifikation.
Defaultwert
PERMITTED
FALSE
FALSE
BasicFile vs. SecureFile
Oracle verspricht mit den neuen SecureFiles – wie schon gesagt – eine verbesserte
Zugriffsperformance. Bei meinen Tests und Vergleichen von Performancewerten stellte ich fest,
dass die Relation stark von der Leistung der Hardware abhängig ist. In der folgenden Tabelle
sind Lese- und Schreibwerte eines 100 MB LOBs auf verschiedener Hardware
www.trivadis.com
Seite 3 / 15
zusammengestellt, installiert war jeweils Oracle 11.1.0.7.0. Oracle Blocksize war 8k und die
Chunksize des BasicFiles 8K. Das LOB stand auf dem Default LOGGING, die Datenbank war
im NOARCHIVELOG Modus. Für die LOBs wurde der Default NOCACHE2 verwendet.
Hardware Lesen, Vergleich Lesen eines LOBs Schreiben des LOBs
von 2 LOBs mittels 100 MB mittels mittels
dbms_lob.compare JDBC thin
dbms_lob.loadfromfile
(2 x 100MB)
A1
A2
B1
B2
BF
1,8 s
17,9 s
4,0 s
2,6 s
SF
1,2 s
5,1 s
11,5 s
1,5 s
BF
3,6 s
12,2 s
2,9 s
2,9 s
SF
3,2 s
4,9 s
3,6 s
3,5 s
BF
4,2 s
4,7 s
22,1 s
8,3 s
SF
1,5 s
4,1 s
79,0 s
75,3 s
Lesen
und
Schreiben, Kopie
eines
LOBs
innerhalb
des
selben Segments
mittels
insert
into
…
select …
BF
SF
5,2 s
3,6 s
15,2 s
6,3 s
12,5 s
79,7 s
6,7 s
76,3 s
Hardware:
A1: Linux x86, 2x Intel Xeon CPU 2.40GHz, I/O Durchsatz mit dd: 80 MB/s
A2: wie A1, Datenfiles jetzt auf nfs, I/O Durchsatz nun 40 MB/s
B1: Solaris 10, Sun Fire V210, 2x UltraSPARC-IIIi 1336 MHz, I/O Durchsatz mit dd: 48 MB/s.
B2: wie B1, Datenfiles jetzt auf einer ramdisk
BF .. BasicFile
SF .. SecureFile
Durch die Tests konnte ganz klar erkannt werden, dass BasicFiles lediglich Ansprüche an das
I/O Subsystem und kaum an die CPU stellen. Das ist bei SecureFiles ganz offensichtlich nicht
so. SecureFiles Performance ist stark von der CPU Leistung abhängig. SecureFiles können nur
mit starken CPUs die BasicFiles auf der Strecke lassen, was sie dann aber auch sehr beachtlich
machen. Ist die CPU hingegen schwach, so wird ein SecureFile Zugriff langsamer als ein
BasicFile Zugriff auf derselben Hardware. Daraus folgt, dass für den Einsatz von SecureFiles
adäquate Hardware verwendet werden muss, um auch den von Oracle prophezeiten
Performancegewinn zu erzielen.
Kurzum SecureFiles sind nur auf aktueller leistungfähiger Hardware schneller als BasicFiles.
LOB Komprimierung
Die LOB Komprimierung ermöglicht nun SecureFiles binär zu komprimieren. Dadurch kann der
Speicherplatz abhängig von Komprimierbarkeit reduziert werden. Es ist als ein Trade Off
zwischen Storage Reduzierung und CPU Nutzung zu verstehen, denn das Komprimieren und
Dekomprimieren verlangt natürlich etwas mehr CPU Ressourcen. Komprimierung kann in zwei
verschiedenen Stufen eingeschaltet werden: MEDIUM und HIGH. Sie steuert letztendlich die
Aggressivität des Komprimierungsalgorithmus, der auf ZLIB3 basiert. Die Komprimierung erfolgt
transparent für die Zugriffsschicht, d.h. bestehende Applikationen brauchen darauf nicht
angepasst zu werden. LOB Komprimierung lässt sich pro Segment also, pro Tabelle, Partition
2
In diesem Tests ging es um die native I/O Performance, daher wurde nicht gecached. Bei einem Caching
des LOBs würden die Ergebnisse natürlich abweichen.
3
Eine Session mit dem Debugger gdb zeigte die verwendete Oracle Kernel Funktion: kgcczlibdo.
www.trivadis.com
Seite 4 / 15
oder Subpartition einstellen. Ohne diese neue LOB Komprimierung stand bisher lediglich eine
manuelle Komprimierung auf Applikationsschicht oder in der Datenbank, z.B. durch das in 10g
eingeführte Package UTL_COMPRESS zu Verfügung.
Betrachten wir folgendes Beispiel: Ein „großes“ Textfile und ein Zip Archiv, welches dieses File
enthält werden betrachtet.
# ls -al
-rw-r--r--rw-r--r--
1 oracle
1 oracle
dba
dba
105000720 Jul 14 11:57 large_txt_file.txt
27063480 Jul 15 16:15 large_txt_file.zip
Die Textdatei ist ca. 100 MB groß. Das mit Standard zip gepackte Archiv ist ca. 26 MB groß. 74
Prozent des Storage wurden damit also eingespart. Jetzt wollen wir sehen, ob das mit der
Oracle Datenbank auch möglich ist. Dafür legen wir 4 Tabellen an. Das LOB Feld in der
Tabelle ist jedesmal anders gespeichert. Einmal als BasicFile, einmal als Standard SecureFile,
einmal als medium komprimiertes SecureFile und zuguterletzt noch als hoch komprimiertes
SecureFile. In diese LOBs laden wir dann die Textdatei und vergleichen die Größen:
Elapsed: 00:00:00.06
SQL> create table lobtest_sf
2
(
3
id number not null,
4
data blob
5 )
6
lob (data) store as securefile datablob_sf
(disable storage in row)
7 ;
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Table created.
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.04
SQL> create table lobtest_comp_med
2
(
3
id number not null,
4
data blob
5 )
6
lob (data) store as securefile
datablob_comp_med (disable storage in row
compress medium)
7 ;
Elapsed: 00:00:05.88
Table created.
1 row created.
Elapsed: 00:00:00.03
SQL> create table lobtest_comp_high
2
(
3
id number not null,
4
data blob
5 )
6
lob (data) store as securefile
datablob_comp_high (disable storage in row
compress high)
7 ;
Elapsed: 00:00:06.54
SQL> insert into lobtest_comp_high
2 select * from lobtest_bf;
Table created.
Elapsed: 00:00:00.02
SQL> select segment_name,bytes from
user_segments
2 where segment_type = 'LOBSEGMENT';
SQL> create table lobtest_bf
2
(
3
id number not null,
4
data blob
5 )
6
lob (data) store as basicfile datablob_bf
(disable storage in row)
7 ;
Table created.
Elapsed: 00:00:00.04
SQL> insert into lobtest_bf (id,data) values
2 (1,empty_blob());
1 row created.
Elapsed: 00:00:00.00
declare
dest_loc
blob;
src_loc
bfile;
amount
integer;
begin
src_loc:=
bfilename('DIR','large_txt_file.txt');
select data into dest_loc
from lobtest_bf for update;
amount := dbms_lob.getlength(src_loc);
dbms_lob.open(src_loc,
dbms_lob.lob_readonly);
dbms_lob.open(dest_loc,
dbms_lob.lob_readwrite);
dbms_lob.loadfromfile(dest_loc,
src_loc, amount);
dbms_lob.close(dest_loc);
dbms_lob.close(src_loc);
end;
/
SQL> insert into lobtest_sf
2 select * from lobtest_bf;
1 row created.
Elapsed: 00:00:03.26
SQL> insert into lobtest_comp_med
2 select * from lobtest_bf;
1 row created.
Elapsed: 00:00:21.13
SQL> commit;
Commit complete.
SEGMENT_NAME
BYTES
------------------------------ ---------DATABLOB_BF
109051904
DATABLOB_SF
189005824
DATABLOB_COMP_MED
36962304
DATABLOB_COMP_HIGH
31719424
Elapsed: 00:00:00.13
www.trivadis.com
Seite 5 / 15
Die längeren Laufzeiten der Inserts erklären sich durch den zusätzlichen Aufwand der
Komprimierung.
Der eigentliche Platzbedarf in den Segmenten ist noch geringer, da in der obigen Query auch
leere vorreservierte Blöcke in den Extents mitgerechnet wurden. Der genaue Platzbedarf lässt
sich mit dem DBMS_SPACE Package ermitteln, welches dafür mit 11g einen neuen Aufruf der
Prozedur SPACE_USAGE bekommen hat. Dafür habe ich folgende PL/SQL Prozedur genutzt.
Die Prozedur erwartet als Eingabe den Segmentnamen und funktioniert für SecureFiles im
aktuellen Schema.
create or replace procedure lobsegmentsize(lobsegment_name varchar2)
as
segment_size_blocks number;
segment_size_bytes number;
used_blocks number;
used_bytes number;
expired_blocks number;
expired_bytes number;
unexpired_blocks number;
unexpired_bytes number;
begin
dbms_space.space_usage(user,lobsegment_name,'LOB',
segment_size_blocks,segment_size_bytes,used_blocks,used_bytes,
expired_blocks,expired_bytes,unexpired_blocks,unexpired_bytes);
dbms_output.put_line(lobsegment_name);
dbms_output.put_line('-----------------');
dbms_output.put_line('segment_size_bytes = '||segment_size_bytes);
dbms_output.put_line('used_bytes = '||used_bytes);
end;
/
SQL> exec lobsegmentsize('DATABLOB_SF');
DATABLOB_SF
----------------segment_size_bytes = 189005824
used_bytes = 106741760
PL/SQL procedure successfully completed.
SQL> exec lobsegmentsize('DATABLOB_COMP_MED');
DATABLOB_COMP_MED
----------------segment_size_bytes = 36962304
used_bytes = 32235520
PL/SQL procedure successfully completed.
SQL> exec lobsegmentsize(DATABLOB_COMP_HIGH');
DATABLOB_COMP_HIGH
----------------segment_size_bytes = 31719424
used_bytes = 27574272
PL/SQL procedure successfully completed.
Der Platzbedarf des hoch komprimierten SecureFiles liegt also auch bei ca. 26 MB und kommt
damit auch an die Rate von zip heran. Wir können also durchaus gute Platzersparnisse erzielen.
Wie gut sich Daten jedoch überhaupt komprimieren lassen hängt natürlich so wie bei jeder
Binärkomprimierung von ihrem Typ ab.
LOB Deduplizierung
Betrachtet man Komprimierungsalgorithmen im Allgemeinen, so gibt es immer ein wesentliches
Prinzip: Wiederholt auftauchende Werte, Sequenzen, Symbole etc. werden nicht wiederholt
gespeichert, sondern dedupliziert. Dieses Prinzip gibt es nun auch in der Oracle Datenbank für
ganze LOBs. Legt man eine Tabelle, Partition oder Subpartition entsprechend an, so werden
sich wiederholende LOBs nur einmal gespeichert. Das geschieht, indem beim Einfügen zur
Laufzeit eine Checksumme berechnet wird. Gibt es diese Checksumme schon im gleichen
www.trivadis.com
Seite 6 / 15
Segment, so wird nur noch eine Referenz auf das schon existierende LOB gespeichert. Die
Checksumme wird defaultmäßig mit SHA1 berechnet.4 Die Erkennung von Duplikaten kann nur
in demselben Segment erfolgen, d.h. es funktioniert nicht partitionsübergreifend und schon gar
nicht tabellenübergreifend. Dieses Feature ist besonders interessant für Dokumentenmanagementsysteme, in welchen Dokumente in Form von LOBs durch zum Beispiel
Multiversions- oder Multiusermanagement redundant gespeichert werden.
Betrachten wir noch einmal das Beispiel von oben:
SQL>
2
3
4
5
6
7
create table lobtest_dedup
(
id number not null,
data blob
)
lob (data) store as securefile datablob_dedup (disable storage in row deduplicate)
;
Table created.
Elapsed: 00:00:00.10
SQL> insert into lobtest_dedup select * from lobtest_sf;
1 row created.
Elapsed: 00:00:06.90
SQL> insert into lobtest_dedup select * from lobtest_sf;
1 row created.
Elapsed: 00:00:03.07
SQL> commit;
Commit complete.
Elapsed: 00:00:00.01
SQL> select count(*) from lobtest_sf;
COUNT(*)
---------1
Elapsed: 00:00:00.00
SQL> select count(*) from lobtest_dedup;
COUNT(*)
---------2
Elapsed: 00:00:00.01
SQL> select segment_name,bytes from user_segments
2 where segment_name in ('DATABLOB_SF','DATABLOB_DEDUP');
SEGMENT_NAME
-------------------DATABLOB_DEDUP
DATABLOB_SF
BYTES
---------151257088
189005824
Elapsed: 00:00:00.57
SQL> exec lobsegmentsize('DATABLOB_SF');
DATABLOB_SF
----------------segment_size_bytes = 189005824
used_bytes = 106741760
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.02
SQL> exec lobsegmentsize('DATABLOB_DEDUP');
DATABLOB_DEDUP
----------------segment_size_bytes = 151257088
used_bytes = 106741760
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.02
4
Der hidden Parameter _kdlxp_dedup_hash_algo legt den Algorithmus fest. SHA2 und MD5 sind
ebenfalls verfügbar.
www.trivadis.com
Seite 7 / 15
Wir können sehen, dass das erneute Einfügen des LOBs, welches schon im Segment vorhanden
ist zu dem gewünschten Effekt führt. Dadurch sparen wir Speicherplatz. Zusätzlich gewinnen
wir in dem Falle eines Inserts wie hier auch an Performance, da „nur“ noch der SHA1 Hash
gespeichert werden muss.
Performance Einflüsse der LOB Komprimierung
LOB Komprimierung und LOB Deduplizierung können wie schon erwähnt einzeln oder auch
kombiniert Anwendung finden. Doch welchen Performance Overhead kosten diese Features?
Wie sollten die LOBs für beste Performance konfiguriert werden? Diese Fragen sollen nun
beleuchtet werden. Ich habe dafür Tests mit LOBs in verschiedenen Szenarien gemacht. Die
LOBs wurden dabei gelesen und geschrieben. Die LOBs wurden mit unterschiedlichen
Einstellungen in Bezug auf ihre Art der Komprimierung, des Caching, der Blocksize des
zugrundeliegenden Tablespaces angelegt.
Leseperformance
Zunächst ein Beispiel anhand einer kleinen „Tuning Session“: Ausgangspunkt ist eine Tabelle
documents mit einem BLOB.
SQL> desc documents
Name
----------------------------------------ID
VERSION
NAME
MIME_TYPE
BYTES
MODIFIED
DATA
Null?
-------NOT NULL
NOT NULL
NOT NULL
Type
---------------------------NUMBER
NUMBER
VARCHAR2(255)
VARCHAR2(30)
NUMBER
DATE
BLOB
Diese Tabelle hat für diesen Test lediglich einen Datensatz mit dem bekannten Textfile:
SQL> select * from documents;
ID
VERSION NAME
MIME_TYPE
BYTES MODIFIED
---------- ---------- -------------------- ------------------------------ ---------- --------1
1 large_txt_file.txt
text/plain
105000720 08-SEP-09
Folgender PL/SQL Block, welche das LOB liest, soll „getuned“ werden.
declare
lob_1 blob;
lob_2 blob;
length number;
begin
select data,dbms_lob.getlength(data) into lob_1,length from documents
where id=1 and version=1;
dbms_lob.createtemporary(lob_2,cache => &1);
dbms_lob.copy(lob_2,lob_1,length);
end;
/
Ca. 10 Sekunden dauert der Lauf für das BasicFile5 mit dem Default cache = false in dem
CREATETEMPORARY Aufruf. Das kann man doch vielleicht noch schneller schaffen: Man
ändert in der PL/SQL Prozedur in dem Aufruf von CREATETEMPORARY den Parameter cache
auf true, und nun sind es knapp 3 Sekunden. Der Grund dafür ist, dass temporary LOBs die
nicht gecached sind, durch I/O Operationen auf dem TEMP Tablespace realisiert werden, egal
5
Hardware: Linux x86, 2x Intel Xeon CPU 2.40GHz, I/O Durchsatz mit dd: 80 MB/s
www.trivadis.com
Seite 8 / 15
wie groß sie sind. In den Wait Events macht sich das durch vermehrtes „direct path read/write
temp“ bemerkbar. Cached temporary LOBs werden hingegen im Memory realisiert, was für
kleine bis mittelgroße LOBs anzustreben ist.
Okay, aber die I/Os auf das gelesene LOB sind auch noch alles direct path reads, d.h. die
gelesenen Blöcke werden nicht gecached. Cached man das Ganze, dann wäre wohl noch mehr
herauszuholen.
SQL> alter table documents modify lob (data) (cache reads);
Table altered.
Nein Irrtum – in meinen Tests verbessert es die Raten nicht.
Wie sieht es nun allerdings mit SecureFiles und komprimierten SecureFiles aus?
alter table documents move lob (data) store as securefile;
alter table documents modify lob (data) (nocache);
Gute 2 Sekunden dauert der PL/SQL Block auf dem SecureFile.
Bringt das Caching hier etwas?
alter table documents modify lob (data) (cache reads);
Nein – nicht wirklich. Die Werte für einen Lauf schwanken hier auf einmal zwischen 2 und 5
Sekunden.
Na gut – dann wird jetzt noch komprimiert:
alter table documents move lob (data) store as securefile (compress high);
alter table documents modify lob (data) (nocache);
Ob es dadurch schneller wird? Wohl kaum, wir haben ja den Overhead des Dekomprimierens.
In der Tat, es dauert ca. 5 Sekunden. Und bringt das Cachen hier etwas?
alter table documents modify lob (data) (cache reads);
Ja, es sind ca. 4 Sekunden! Auch schon im ersten Lauf ohne „Cache Warmup“. Aber warum?
Warum bringt es was bei komprimierten Daten? Diese Frage wird später beantwortet.
Zuguterletzt war da ja noch der Tablespace mit der größeren Blocksize:
alter table documents move lob (data) store as securefile (compress high tablespace users_16k);
alter table documents modify lob (data) (nocache);
Ja – das bringt auch etwas. Knapp 3 Sekunden läuft der PL/SQL Block nun.
Warum hat das Cachen auf der komprimierten Tabelle nun etwas gebracht?
In meinen Tests bemerkte ich, dass die Werte für „physical read bytes“ in der View V$SESSTAT
höher lagen, als das BLOB eigentlich groß war, und das obwohl ich erwartete, dass es durch die
Komprimierung ja kleiner sein muss. Das LOB ist im Segment defacto ja auch kleiner, wie wir
vorher schon gesehen haben. D.h. es kann nur so sein, dass gewisse Blöcke mehrfach gelesen
werden. Und diese „dunkle“ Ahnung hat sich bestätigt, als ich die Leseoperationen mit einem
Trace mittels DBMS_MONITOR.SESSION_TRACE_ENABLE untersucht habe. Folgendermaßen
sah das Lesen eines komprimierten LOBs aus:
www.trivadis.com
Seite 9 / 15
Lesen eines medium komprimierten LOBs
210000
209000
Blocknummer
208000
207000
206000
205000
204000
203000
Zeit
In der Grafik sind von den Multiblock I/Os Operationen (direct path read) jeweils der Startblock
angegeben. Der von Oracle gewählte Algorithmus zum Dekomprimieren erfordert offenbar das
wiederholte Lesen von Blöcken. Warum das so ist, konnte oder wollte Oracle mir in einem
laufenden Service Request bis heute nicht erklären. Nun, und durch das wiederholte Lesen der
Blöcke bringt das Cachen natürlich etwas. Folgendes Beispiel zeigt das deutlich, hier werden
zwei medium komprimierte LOB mittels DBMS_LOB.COMPARE verglichen:
SQL> REM eine zweite Row mit demselben LOB erzeugen
SQL> insert into documents select 1,2,name,mime_type,bytes,modified,data from documents;
1 row created.
SQL> commit;
Commit complete.
SQL> alter table documents move lob (data) store as securefile (compress medium);
Table altered.
SQL> REM neu connecten um v$mystat zu "initialisieren"
SQL> connect scott/tiger
Connected.
SQL> set serveroutput on timing on
SQL> column name format a30
SQL> column value format 999999999999999
SQL> REM Wie groß ist das LOB-Segment?
SQL> exec lobsegmentsize('DATABLOB');
DATABLOB
----------------segment_size_bytes = 86179840
used_bytes = 64462848
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
www.trivadis.com
Seite 10 / 15
SQL> REM der dbms_lob.compare Aufruf
SQL> declare
2
lob_1 blob;
3
lob_2 blob;
4
retval integer;
5 begin
6
select data into lob_1 from documents
7
where id=1 and version=1;
8
select data into lob_2 from documents
9
where id=1 and version=2;
10
retval := dbms_lob.compare(lob_1, lob_2);
11
if retval = 0 then
12
dbms_output.put_line('equal');
13
else
14
dbms_output.put_line('not equal');
15
end if;
16 end;
17 /
equal
PL/SQL procedure successfully completed.
Elapsed: 00:00:47.76
SQL> REM Wieviel wurde gelesen?
SQL> select name, value from v$mystat natural join v$statname where name = 'physical read bytes';
NAME
VALUE
------------------------------ ---------------physical read bytes
11993120768
Elapsed: 00:00:00.00
SQL> REM Und jetzt das LOB auf CACHE READS setzen
SQL> alter table documents modify lob (data) (cache reads);
Table altered.
Elapsed: 00:00:02.33
SQL> REM den Buffer Cache ausleeren um etwaige Seiteneffekte auszuschließen
SQL> conn / as sysdba
Connected.
SQL> alter system flush buffer_cache;
System altered.
Elapsed: 00:00:01.59
SQL> REM neu connecten um v$mystat zu "initialisieren"
SQL> conn scott/tiger
Connected.
SQL> set serveroutput on
SQL> REM der dbms_lob.compare Aufruf
SQL> declare
2
lob_1 blob;
3
lob_2 blob;
4
retval integer;
5 begin
6
select data into lob_1 from documents
7
where id=1 and version=1;
8
select data into lob_2 from documents
9
where id=1 and version=2;
10
retval := dbms_lob.compare(lob_1, lob_2);
11
if retval = 0 then
12
dbms_output.put_line('equal');
13
else
14
dbms_output.put_line('not equal');
15
end if;
16 end;
17 /
equal
PL/SQL procedure successfully completed.
Elapsed: 00:00:18.10
SQL> REM Und wieviel wurde jetzt von Disk gelesen?
SQL> select name, value from v$mystat natural join v$statname where name = 'physical read bytes';
NAME
VALUE
------------------------------ ---------------physical read bytes
64438272
Elapsed: 00:00:00.00
Durch das Caching des LOBs wurden die physical reads von über 11 GB !! auf 61 MB reduziert.
Das entspricht einer I/O Reduktion um 99,5 Prozent !!!. Die Laufzeit hat sich um ca. 60 Prozent
verkürzt. Das sind enorme Faktoren.
www.trivadis.com
Seite 11 / 15
In folgender Tabelle sind die gemessenen Werte für verschiedene LOB Einstellungen
zusammengefasst:
LOB Einstellungen
NOCOMPRESS
KEEP_DUPLICATES
COMPRESS
MEDIUM
KEEP_DUPLICATES
COMPRESS HIGH
KEEP_DUPLICATES
NOCOMPRESS
DEDUPLICATE
COMPRESS
MEDIUM
DEDUPLICATE
COMPRESS HIGH
DEDUPLICATE
NOCACHE
Physical Zeit
LOB
Segment Reads in in s
MB
Größe
in MB
204
204
1,3
CACHE READS
Physical Zeit
Reads in in s
MB
I/O
Einsparung
in Prozent
Zeit
Einsparung
in Prozent
204
2,9
0
-123
61
11438
53,0
61
19,7
99,5
62,8
53
10553
48,7
53
18,6
99,5
61,8
102
12424
38,5
102
2,2
99,2
94,3
31
882
6,5
31
4,9
96,5
24,7
26
791
7,0
26
4,4
96,7
37,1
Die Einstellung „CACHE“ bei den LOBs ist nicht extra ausgewiesen, da sich bei lesenden
Operationen der Effekt von „CACHE“ nicht von dem von „CACHE READS“ unterscheidet.
Gut – diese fiktiven „Tuning“ Sessions bezogen sich lediglich auf das Lesen mittels DBMS_LOB.
Dennoch werden hier einige wichtige Grundsätze klar:
- Caching in der API oder am Client sind ein wesentlicher Aspekt.
- Caching von temporären LOBs (hier in DBMS_LOB.CREATETEMPORARY) steigert die
Performance, da TEMP Tablespace I/O-Operationen vermieden werden
- Eine größere Blocksize verbessert die Leseperformance von großen LOBs6. Außerdem ist
hier noch der Aspekt des separaten Caches anzubringen. Durch einen eigenen Cache,
der für das Betreiben von Tablespaces mit einer Blocksize verschieden der Datenbank
Default Blocksize notwendig ist, wird die Cache Hit Ratio des Default Buffer Cache
nicht durch etwaiges LOB Caching beeinflusst. Dadurch wird die Performance für
„normale“ Tabellen nicht in Gefahr gebracht.
- Caching am Server lohnt sich im Spezialfall des Lesens von komprimierten und/oder
deduplizierten LOBs – und das nicht nur bei wiederholtem Lesen.
Erstaunlich ist, dass auch die Deduplizierung diesen Effekt mit dem multiplen Lesen mit sich
bringt, welcher im Falle NOCOMPRESS noch relativ dramatisch ist, sich jedoch mit der
Komprimierung dann etwas relativiert, auch schon ohne Caching.
Ähnliche Performancekennzahlen und -trends wurden auch beim lesenden Zugriff mit JDBC
festgestellt, sowohl für JDBC OCI als auch für JDBC Thin Zugriffe. Daher kann ausgeschlossen
werden, dass es sich bei den oben gemessenen Werten „nur“ um ein Phänomen im
Zusammenhang mit der DBMS_LOB API handelt.
6
Vorsicht: Verwenden Sie keine Blocksize für LOBs die größer ist als die durchschnittliche Größe der
LOBs. Das verschwendet zu viel Platz.
www.trivadis.com
Seite 12 / 15
Schreibperformance
Wir machen mit dem oberen Beispiel weiter und wollen nun schließlich noch die
Schreibperformance untersuchen. Die 2 Datensätze aus der Tabelle werden dabei mittels Insert
in eine vorbereitete Tabelle kopiert und dabei die Zeit sowie die physical reads und writes
gemessen. Die Quelltabelle wird zunächst wieder auf Standard SecureFile zurückgestellt. Dann
wird die neue Table erstellt und die Daten hineinkopiert:
SQL> alter table documents move lob (data) store as securefile (nocache nocompress keep_duplicates);
Table altered.
Elapsed: 00:00:12.71
SQL> CREATE TABLE documents_comp_med
2
(
3
ID NUMBER NOT NULL ENABLE,
4
VERSION NUMBER NOT NULL ENABLE,
5
NAME VARCHAR2(255) NOT NULL ENABLE,
6
MIME_TYPE VARCHAR2(30),
7
BYTES NUMBER,
8
MODIFIED DATE,
9
DATA BLOB
10 )
11
LOB (DATA) STORE AS SECUREFILE DATABLOB_COMP_MED (DISABLE STORAGE IN ROW COMPRESS MEDIUM)
12 ;
Table created.
Elapsed: 00:00:00.06
SQL> REM neu connecten um v$mystat zu "initialisieren"
SQL> conn scott/tiger
Connected.
SQL> insert into documents_comp_med select * from documents;
2 rows created.
Elapsed: 00:00:26.32
SQL> commit;
Commit complete.
Elapsed: 00:00:00.11
SQL> select name, value from v$mystat natural join v$statname
2 where name in ('physical read bytes','physical write bytes','redo size');
NAME
VALUE
------------------------------ ---------physical read bytes
213950464
physical write bytes
64438272
redo size
240432
Elapsed: 00:00:00.01
SQL> alter table documents_comp_med modify lob (data) (cache);
Table altered.
Elapsed: 00:00:00.04
SQL> truncate table documents_comp_med;
Table truncated.
Elapsed: 00:00:04.72
SQL> REM neu connecten um v$mystat zu "initialisieren"
SQL> conn scott/tiger
Connected.
SQL> insert into documents_comp_med select * from documents;
2 rows created.
Elapsed: 00:00:33.02
SQL> commit;
Commit complete.
Elapsed: 00:00:00.01
SQL> select name, value from v$mystat natural join v$statname
2 where name in ('physical read bytes','physical write bytes','redo size');
NAME
VALUE
------------------------------ ---------physical read bytes
214130688
www.trivadis.com
Seite 13 / 15
physical write bytes
redo size
0
64597740
Elapsed: 00:00:00.01
Es ist also festzustellen, dass das Caching hier das Schreiben verzögert, also eher einen
negativen Effekt hat. Folgende Tabelle fasst die Performancedaten für diesen Lauf und für alle
anderen Arten von Tabellen zusammen. Quelle der beiden Datensätze war immer die gleiche
Tabelle mit dem Standard SecureFile. Da die Zeiten hier teilweise recht stark schwankten, habe
ich hier die durchschnittlichen Werte aus 10 Läufen notiert:
LOB Einstellungen der LOB
Zieltabelle
Segment
Größe in
MB
NOCOMPRESS
204
KEEP_DUPLICATES
COMPRESS MEDIUM 61
KEEP_DUPLICATES
COMPRESS
HIGH 53
KEEP_DUPLICATES
NOCOMPRESS
102
DEDUPLICATE
COMPRESS MEDIUM 31
DEDUPLICATE
COMPRESS
HIGH 26
DEDUPLICATE
NOCACHE
Physical
Redo
Writes in Size
MB
in MB
Ø
Zeit
in s
CACHE
Physical
Redo
Ø
Writes in Size in Zeit
MB7
MB
in s
204
0,6
8,6
0
206
66,6
61
0,3
24,0
0
62
34,2
53
0,2
70,4
0
53
66,3
102
0,3
7,9
0
103
36,5
31
0,1
26,9
0
31
22,9
26
0,1
63,6
0
26
58,2
Die Einstellung „CACHE READS“ bei den LOBs ist nicht extra ausgewiesen, da sich bei
schreibenden Operationen der Effekt von „CACHE READS“ nicht von dem von „NOCACHE“
unterscheidet. Alle LOBs standen auf normalem LOGGING, d.h. über die Redo Logs wurde
sichergestellt, dass sie wiederherstellbar / recoverable sind.
Diese Zahlen offenbaren nun recht interessante Erkenntnisse: Wie schon erwähnt – bei der
Tabelle mit dem medium komprimierten LOBs macht das Caching fürs Schreiben wenig Sinn.
Die Laufzeit erhöht sich im Schnitt um 10 Sekunden. Jedoch kippt dieses Bild bei Steigerung
der Komprimierungsrate und/oder bei der Hinzunahme von Deduplizierung, auch wenn es
nicht zu enormen Performancesteigerungen kommt. Jedoch Vorsicht: Die Raten für das
Schreiben in cached LOBs sind auch stark von der Performance des Log Writers abhängig, z.B.
von der Anzahl der Redo Log Member pro Redo Log Gruppe. In meinen Tests wurde nicht
gespiegelt. In Produktionsumgebungen sollte aber unbedingt gespiegelt werden, d.h. dort
relativiert sich das Bild wieder. Ein weiterer Aspekt ist, dass es sich hier um ein großes
Textdokument handelte, welches sehr stark komprimiert werden konnte.
Alles in allem denke ich, dass das Cachen von SecureFile LOBs schon beim Schreiben nicht
generell zu empfehlen ist. Es mag aber den einen oder anderen Ausnahmefall geben, bei
welchem es sich lohnt. Dieses wäre dann aber für die jeweilige Applikation in ausführlichen
Tests zu verifizieren.
Das Schreiben in LOBs mittels DBMS_LOB.LOADFROMFILE oder mit jdbc zeigte ähnliche
Resultate. Im Falle der Verwendung von „großen“ LOBs ist eine höhere Blocksize für die LOB
Tablespaces auch im Hinblick auf die Schreiboperationen zu empfehlen.
7
Im Falle „Cache“ wird nicht von der Server Session direkt in die Datafiles geschrieben. Das übernimmt
hier der Database Writer mit einer Verzögerung. Daher misst die Session keinerlei „physical write bytes“.
www.trivadis.com
Seite 14 / 15
Empfehlungen zum Setup von komprimierten LOBs
Folgende Empfehlungen für eine beste Performance ergeben sich nun unter anderem aus
meinen Tests:
- Verwenden Sie komprimierte LOBs nur auf aktueller leistungsfähiger Hardware.
- Verwenden Sie „enable storage in row“ nur, wenn in die Majorität der Queries auf der
Table das entsprechende LOB mit abfragt, ansonsten verwenden Sie „disable storage in
row“.
- Verwenden Sie eigene Tablespaces für die großen LOBs und geben Sie diesen eine
höhere Blocksize. Das hat auch den Vorteil, dass damit für die LOBs ein weiterer
eigener Buffer Cache entsteht.
- Setzen Sie die komprimierten LOBs auf CACHE READ.
- Setzen sie die Parameter für die LOB Retention nur so gering wie nötig.
- Erwägen Sie den Einsatz von FILESYSTEM_LIKE_LOGGING oder gar NOLOGGING
nachdem Sie sich über das Risiko von Nologging Operationen bewusst sind.
- Testen und verifizieren Sie Ihr Setup für die beste Performance.
Fazit
Oracle LOB Komprimierung und Deduplizierung sind eine gute Möglichkeit Speicherplatz zu
sparen. Oracle verspricht auf seiner Homepage8 auch die Performance zu verbessern. Zu
diesem Punkt muss man jedoch ganz klar sagen, dass es von vielen Faktoren abhängt, ob die
Performance wirklich besser wird. Sie kann unter gewissen Umständen auch schlechter werden.
Gute Tests bevor man das Feature in Produktion einsetzt sind daher wichtig. Immer viel Freude
an Ihren komprimierten LOBs wünscht
Mathias Zarick
Trivadis GmbH
Millennium Tower
Handelskai 94-96
A-1200 Wien
Tel.: +43 1 332 35 31 00
Fax: +43 1 332 35 34
[email protected]
www.trivadis.com
Kontaktieren Sie mich bitte, wenn Sie weitere Details oder Hilfe beim Setup von komprimierten
LOBs benötigen.
Quellenangabe
[1] Oracle, Oracle Database SecureFiles and Large Objects Developer's Guide, 11g Release 1,
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28393.pdf
[2] Oracle, Oracle Database PL/SQL Packages and Types Reference, 11g Release 1,
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28419.pdf
8
http://www.oracle.com/database/advanced-compression.html
www.trivadis.com
Seite 15 / 15
Herunterladen