Wir haben in den letzten Blogeinträgen schon Einiges zum Thema Oracle Database 12
veröffentlicht. Auch in diesem Blog wollen wir uns wieder einem neuen Oracle Text 12c Feature widmen. Es geht dabei um neue Möglichkeiten innerhalb der Text Indexstruktur, Änderungen an dem Default Speicherverhalten vorzunehmen, um unter Umständen bei Indexzugriffen weniger I/Os durchführen zu müssen. Gemeint ist damit die $I Tabelle und die Spalte TOKEN_INFO.
Welche Informationen speichert die Spalte TOKEN_INFO? Zur Erinnerung: Jedes Wort (besser Token) wird über die DOCID (Dokumenten ID des Dokuments, das das Token enthält) und die entsprechenden Wortpositionen in diesem Dokument gefunden. Beide Informationen werden in der Spalte TOKEN_INFO in binärer Form gespeichert. Standardmässig ist diese Spalte vom Datentyp BLOB und kann Informationen bis zu 4000 Bytes (dies ist eine interne Begrenzung) speichern. Müssen viele Informationen (mehr als 4000 Bytes) in der TOKEN_INFO Spalte gespeichert werden, werden neue Zeilen hinzugefügt. Die Idee in 12c ist nun, weniger Zeilen für große TOKEN_INFO Einträge speichern zu müssen. Aber schauen wir uns zuerst das Standrrdverhalten an einem einfachen Beispiel an.
SQL> create table my_table( id number primary key, text varchar2(2000) );
Table created.
SQL> create index my_index on my_table( text ) indextype is ctxsys.context;
Index created.
SQL> desc DR$MY_INDEX$I
Name Null? Type
----------------------------------------- -------- ----------------------------
TOKEN_TEXT NOT NULL VARCHAR2(64)
TOKEN_TYPE NOT NULL NUMBER(10)
TOKEN_FIRST NOT NULL NUMBER(10)
TOKEN_LAST NOT NULL NUMBER(10)
TOKEN_COUNT NOT NULL NUMBER(10)
TOKEN_INFO BLOB
Überprüft man die genaue Definition der Tabelle DR$MY_INDEX$I, kann man feststellen, dass sich die Defaultspeicherung von LOBs in 12c geändert hat und nun statt der Basicfile eine
Securefile Speicherung vorliegt. Für diejenigen, die es genau wissen wollen: Dies liegt an dem geänderten Parameterwert PREFERRED für den Initialisierungsparameter DB_SECUREFILE.
SQL> set long 10000 pagesize 100
SQL> execute DBMS_METADATA.SET_TRANSFORM_PARAM(TRANSFORM_HANDLE=>-
DBMS_METADATA.SESSION_TRANSFORM, name=>'STORAGE', value=>false);
SQL> SELECT DBMS_METADATA.GET_DDL(object_type=>'TABLE', name=>'DR$MY_INDEX$I') AS ausgabe
FROM dual;
AUSGABE
--------------------------------------------------------------------------------
CREATE TABLE "SCOTT"."DR$MY_INDEX$I"
( "TOKEN_TEXT" VARCHAR2(64) NOT NULL ENABLE,
"TOKEN_TYPE" NUMBER(10,0) NOT NULL ENABLE,
"TOKEN_FIRST" NUMBER(10,0) NOT NULL ENABLE,
"TOKEN_LAST" NUMBER(10,0) NOT NULL ENABLE,
"TOKEN_COUNT" NUMBER(10,0) NOT NULL ENABLE,
"TOKEN_INFO" BLOB
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
TABLESPACE "USERS"
LOB ("TOKEN_INFO") STORE AS SECUREFILE (
TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192
NOCACHE LOGGING NOCOMPRESS KEEP_DUPLICATES )
MONITORING
Dies ändert allerdings noch nichts an der internen Begrenzung auf 4000 Bytes. Ein einfaches Beispiel demonstriert das Standardverhalten - auch in 12c. Dazu legen wir eine einfache Tabelle mit einer Spalte an und speichern 5000 Mal den Eintrag HELLO ab.
SQL> drop table my_table purge;
Table dropped
SQL> create table my_table (text varchar2(80));
Table created
SQL> begin
for i in 1 .. 5000 loop
insert into my_table values ('hello');
commit;
end loop;
end;
/
SQL> create index my_index on my_table (text) indextype is ctxsys.context;
Index created
Selektieren wir nun die $I Tabelle, stellen wir fest, dass 5 Zeilen für das Token HELLO verwendet wurden - mit einer Länge von 2499 bzw. 3501 Bytes.
SQL> column token_text format a15
SQL> select token_text, length(token_info) from dr$my_index$i;
TOKEN_TEXT LENGTH(TOKEN_INFO)
--------------- ------------------
HELLO 2499
HELLO 3501
HELLO 3501
HELLO 3501
HELLO 3501
Nun wenden wir das neue Feature BIG_IO an, dass diese Grenze aufheben soll. Dazu ist die neue Option
BIG_IO als Attribute in der
Preference BASIC_STORAGE auf
TRUE zu setzen.
SQL> begin
ctx_ddl.create_preference( 'my_storage', 'BASIC_STORAGE' );
ctx_ddl.set_attribute ( 'my_storage', 'BIG_IO', 'true' );
end;
/
-- entweder Neuanlegen des Index oder mit ALTER INDEX
SQL> alter index my_index rebuild parameters ('replace storage my_storage');
Index altered.
Wenn wir nun die Token Information überprüfen, finden wir nur noch einen einzigen (!) Eintrag vor - allerdings der Länge 15023.
SQL> select token_text, length(token_info) from dr$my_index$i;
TOKEN_TEXT LENGTH(TOKEN_INFO)
--------------- ------------------
HELLO 15023
BIG_IO sorgt also dafür, dass wir unter Umständen weniger Einträge pro Token in der $I Tabelle speichern. Dies kann dann dabei helfen, die Zugriffe auf große Indexfragmente zu reduzieren.