Oracle 12c: MAX_STRING_SIZE=EXTENDED – wo und wie werden die Daten abgespeichert?

22. Mai 2014 Aus Von Markus Flechtner

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.