Oracle 12c: MAX_STRING_SIZE=EXTENDED – wo und wie werden die Daten abgespeichert?
Oracle Database 12c erlaubt bekanntermassen, dass VARCHAR2-Spalten länger als 4.000 Bytes sein dürfen. Bedingung dafür ist, dass der Parameter MAX_STRING_SIZE auf EXTENDED gesetzt wird und dass das Skript utl32k.sql ausgeführt wird (Einzelheiten und vollständige Dokumentation siehe z.B. Oracle 12c-Reference zu „MAX_STRING_SIZE“.
Bekannt ist auch, dass Strings länger als 4.000 Bytes abgespeichert werden. Das zeigt die folgende kurze Demo:
SQL> show parameter max_string_size
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
max_string_size string EXTENDED
SQL> create user LOBTEST identified by LOBTEST default tablespace USERS temporary tablespace TEMP;
User created.
SQL> grant connect,resource to LOBTEST;
Grant succeeded.
SQL> alter user LOBTEST quota unlimited on USERS;
User altered.
SQL> connect LOBTEST/LOBTEST
Connected.
SQL> create table LOBTEST1 (A varchar2(4000));
Table created.
SQL> insert into LOBTEST1(A) values ('TEST');
1 row created.
SQL> select segment_name,segment_type from user_segments
SEGMENT_NAME SEGMENT_TYPE
-------------------- ------------------
LOBTEST1 TABLE
SQL> drop table LOBTEST1 purge;
Table dropped.
SQL> create table LOBTEST2 (A varchar2(4001));
Table created.
SQL> insert into LOBTEST2(A) values ('TEST');
1 row created.
SQL> select segment_name,segment_type from user_segments;
SEGMENT_NAME SEGMENT_TYPE
------------------------------ ------------------
LOBTEST2 TABLE
SYS_IL0000088585C00001$$ LOBINDEX
SYS_LOB0000088585C00001$$ LOBSEGMENT
SQL> drop table LOBTEST2 purge;
Table dropped.
So weit, so gut.
Nehmen wir aber mal an, wir haben eine bestehende Tabelle und wollen die Länge einer Spalte auf mehr als 4.000 Bytes vergrößern:
SQL> create table LOBTEST3 (A varchar2(4000));
Table created.
SQL> insert into LOBTEST3(A) values ('TEST');
1 row created.
SQL> select segment_name,segment_type from user_segments;
SEGMENT_NAME SEGMENT_TYPE
------------------------------ ------------------
LOBTEST3 TABLE
SQL> alter table LOBTEST3 modify (A varchar2(4001));
Table altered.
SQL> select segment_name,segment_type from user_segments;
SEGMENT_NAME SEGMENT_TYPE
------------------------------ ------------------
LOBTEST3 TABLE
Diesmal geht es also ohne LOB-Segment.
Aber vielleicht wird das LOB-Segment erst angelegt, wenn ein passender Wert in die Tabelle eingefügt wird:
SQL> insert into LOBTEST3 select rpad('A',4001,'B') from dual;
1 row created.
SQL> commit;
Commit complete.
SQL> select length(A) from LOBTEST3;
LENGTH(A)
----------
4
4001
Und jetzt ein Blick in die USER_SEGMENTS:
SQL> select segment_name,segment_type from user_segments;
SEGMENT_NAME SEGMENT_TYPE
------------------------------ ------------------
LOBTEST3 TABLE
.. und ich frage mich, wo sind die Daten abgeblieben?
Sie sind im Datafile
oracle@nf12cdba:/u01/oradata/NCDB/ [NCDB] grep -i ABBBBB users01.dbf
Binary file users01.dbf matches
aber anscheinend nicht in einem LOB-Segment des Users .. – sie bleiben also anscheinend „inline“.
Ergänzung (26.05.2014):
Mein Kollege Ludovico Caldara hat sich in seinem Blog auch mit dem Thema beschäftigt:
http://www.ludovicocaldara.net/dba/extended-data-types-storage/
Und Franck Pachot zeigt in seinem Blog (http://www.dbi-services.com/index.php/blog/entry/12c-extended-datatypes-better-than-clob), dass die Performance der Extended DataTypes besser ist als die CLOB-Performance.