Posts mit dem Label 12c werden angezeigt. Alle Posts anzeigen
Posts mit dem Label 12c werden angezeigt. Alle Posts anzeigen

Dienstag, 8. April 2014

Oracle12c: Verändertes Verhalten bei Datastore Triggern

Falls Sie einen Multicolumn Datastore oder einen User Datastore nutzen, kann folgender Blogeintrag ganz nützlich sein. Es geht um das veränderte Verhalten bei Verwendung von Datenbank Trigger und was man tun kann, um das alte Verhalten wiederherzustellen. Als Erinnerung bzw. als Grundlage nehmen wir den Blog Mehrere Tabellenspalten indizieren: MULTICOLUMN_DATASTORE.
Hier kurz noch einmal der Code zur Erinnerung:

-- Anlegen der Tabelle
drop table  produktions_hinweise purge;
create table produktions_hinweise(
  fall_id               number(10),
  kommentar_werk        varchar2(4000),
  kommentar_controlling varchar2(4000),
  hinweise_produktion   clob);

-- Einfügen eines Satzes
insert into produktions_hinweise 
(fall_id, kommentar_werk, kommentar_controlling, hinweise_produktion) 
values 
(1,'Auslastung','Abschreibungen', 'Spezialmaschine');
Um einen Multicolumn Datastore nutzen zu können, muss zunächst eine sogenannte Preference erzeugt werden; hier werden die Spalten, welche gemeinsam indiziert werden sollen, konfiguriert.

begin
  ctx_ddl.create_preference(
    preference_name => 'kommentare_store'
   ,object_name     => 'MULTI_COLUMN_DATASTORE'
  );
  ctx_ddl.set_attribute(
    preference_name => 'kommentare_store'
   ,attribute_name  => 'columns'
   ,attribute_value => 'KOMMENTAR_WERK, KOMMENTAR_CONTROLLING, HINWEISE_PRODUKTION'
  );
end;
/

Man kann nun eine der drei Dokumentspalten zur Indizierung nehmen; aus Gründen der Übersichtlichkeit empfiehlt es sich jedoch, eine eigene "Dummy"-Spalte zu erzeugen.

alter table produktions_hinweise add (indexspalte char(1));
Nun Erzeugen wir einen Index - die Preferences geben den Datastore, die Section Group und das Synchronisieren nach dem COMMIT an.

create index idx_kommentare on produktions_hinweise (indexspalte)
indextype is ctxsys.context parameters 
('datastore kommentare_store 
  section group CTXSYS.AUTO_SECTION_GROUP
  SYNC (ON COMMIT)');
Wir haben nun einen Index auf einer spezifischen Spalte; der Index wird allerdings nur verändert, wenn diese Spalte sich ändert. Damit der Index aber immer beim UPDATE auf einer anderen Spalte (hier beispielsweise KOMMENTAR_WERK) verändert wird, konnte man vor 12c einen BEFORE UPDATE Trigger verwenden wie folgendes Beispiel zeigt:

create or replace trigger trg_produktions_hinweise
before update on produktions_hinweise
for each row
begin
  :new.indexspalte := :new.indexspalte;
end;
/
Ändert man nun irgendeine Spalte mit anschliessendem COMMIT (in unserem Beispiel KOMMENTAR_WERK), wird der Index synchronisiert. Dieses Verhalten hat sich in 12c geändert, nachdem Bug 14155722 gefixed wurde! Oracle Text hat nämlich implizit folgende Funktion verwendet - Zitat aus dem Bug:
"If an enabled "BEFORE UPDATE" row trigger references a column A but that column A is not updated by the trigger, only referenced, logminer reports SQL_REDO as updating the column A to itself when some other column B is updated. This issue has been reported in the Bug 7720026: SQL_REDO SHOWS UPDATES OF COLUMNS NOT IN UPDATE STATEMENT"
Trigger prüfen nun als Fix zu Bug 14155722 den "before" und "after" Zustand aller referenzierten Spaltenwerte. Falls die Spalte sich NICHT verändert hat, dann findet auch KEIN Index Update statt. Dies bedeutet, dass unser Trigger kein Index Update initiiert, wenn eine andere Spalte verändert wird.

Was kann man tun? Laut Roger Fords (Productmanager von Oracle Text) Blogeintrag kann man in der Session oder im ganzen System ein Fix Control verwenden.
alter session set "_fix_control"='14155722:OFF';
-- oder
alter system set "_fix_control"='14155722:OFF';
Was ist noch einmal ein Fix Control (Bezeichnung:_FIX_CONTROL)? "_FIX_CONTROL" ist ein spezieller "hidden" Parameter - eingeführt mit 10.2.0.2 - mit dem man Bug Fixes ein- und ausschalten kann. Der Default (ON oder OFF) für einen Fix wird meist über den Wert von OPTIMIZER_FEATURES_ENABLE bestimmt. Ansehen kann man sich die Einstellungen übrigens mit V$SYSTEM_FIX_CONTROL oder über V$SESSION_FIX_CONTROL. Mehr dazu findet sich auch in My Oracle Support Note 567171.1.

Zum Schluss treten wir natürlich noch den Beweis in 12c an :) ...
-- Fix Control setzen 
alter session set "_fix_control"='14155722:OFF';
--Überprüfung, VALUE 0 bedeutet OFF
SQL> select * from V$SESSION_FIX_CONTROL where bugno=14155722;

SESSION_ID      BUGNO      VALUE
---------- ---------- ----------
SQL_FEATURE
----------------------------------------------------------------
DESCRIPTION
----------------------------------------------------------------
OPTIMIZER_FEATURE_ENABLE       EVENT IS_DEFAULT     CON_ID
------------------------- ---------- ---------- ----------
        67   14155722          0
QKSFM_CBO_14098180
check whether outbinds were modified in before row UPDATE trigge
8.0.0                              0          0          0
-- ein Update
update produktions_hinweise set kommentar_werk='TTT';
commit; 
-- die Abfrage
select fall_id from produktions_hinweise
where contains(
  indexspalte, 
  '(Spezialmaschine WITHIN (HINWEISE_PRODUKTION)) and 
   (Abschreibungen WITHIN (KOMMENTAR_CONTROLLING)) and 
   (TTT WITHIN (KOMMENTAR_WERK))'
)>0
/
   FALL_ID
----------
         1

Und das alte Verhalten ist wiederhergestellt.

Dienstag, 8. Oktober 2013

Oracle Text in Oracle 12c: Automatic Near Real-Time Index

Oracle Database 12c steht schon seit einiger Zeit zur Verfügung und wie schon angesprochen, wollen wir im Rahmen unserer Blogpostings die neuen Features nach und nach beschreiben. Dieses Mal geht es um das sogenannte Feature "Automatic Near Real-Time Indexing". Dabei geht es um die typische Anforderung den Index möglich aktuell zu halten - sogar bei hoher Änderungsrate. Hoher Aktualitätsanspruch bedeutet allerdings häufiges Synchronisieren und führt natürlich zu hoher Fragmentierung bzw. zu vermehrtem und länger andauernden OPTIMIZE Operationen.

12c löst dieses Dilemma mit dem neuen Konzept des "two-level" Index bzw. auch unter dem Feature Name "near real time index" bekannt. Dies erlaubt einen kleinen, fragmentierten Stage Index, der alle aktuellen Veränderungen enthält, vorzuhalten, ohne Änderungen an dem großen Index vornehmen zu müssen. Die Idee dabei ist, dass der Stage Index klein genug ist, um in die SGA zu passen. Die Daten können dann nach und nach vom Stage Index zum Hauptindex verlagert werden. Dies geschieht mit einem neuen MERGE Modus für Indizes.

Folgendes Beispiel zeigt wie das Feature genutzt werden kann. Zuerst stellen wir eine leere Tabelle zur Verfügung.
drop table texttabelle
/
drop sequence s
/
create sequence s
/
create table texttabelle(
  id          number(10) default s.nextval,
  dokument varchar2(1000))
/
Realisiert wird das Feature dann mit der zusätzlichen Storage Option STAGE_ITAB.
exec ctx_ddl.drop_preference ('my_storage');
exec ctx_ddl.create_preference('my_storage', 'BASIC_STORAGE');
exec ctx_ddl.set_attribute ('my_storage', 'STAGE_ITAB', 'true');
Nun erzeugen wir den Index.
create index my_index on texttabelle (dokument) 
indextype is ctxsys.context
parameters( 'storage my_storage sync (on commit)');
Überprüfen wir die erzeugten Tabellenobjekte, stellen wir fest, dass zusätzlich eine neue Tabelle mit Namen DR$MY_INDEX$G generiert wurde, die die gleiche Struktur wir die $I Tabelle besitzt.
SQL> select * from tab
  2  /

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
DR$MY_INDEX$G                  TABLE
DR$MY_INDEX$N                  TABLE
DR$MY_INDEX$R                  TABLE
DR$MY_INDEX$K                  TABLE
TEXTTABELLE                    TABLE
DR$MY_INDEX$I                  TABLE

6 rows selected.
Darüberhinaus werden weitere Objekte wie zum Beispiel ein $H B-tree Index auf der $G Tabelle erzeugt - dieser erfüllt die gleiche Aufgabe wie der $X Index auf der $I Tabelle.

Nun fügen wir einfach zwei Zeilen ein und schließen jeweils mit COMMIT ab.
insert into texttabelle (dokument) values 
         ('A-Partei gewinnt Wahl in Hansestadt');
commit;
insert into texttabelle (dokument) values 
         ('Terror in Nahost: Kriminalität steigt immer weiter an'); 
commit;
Überprüfen wir die Inhalte der beiden Tabellen, stellen wir fest, dass die $I Tabelle leer ist, wohingegen die $G Tabelle befüllt wurde. Neue Inhalte werden also nicht mehr direkt in der $I Tabelle geschrieben, sondern in der $G Tabelle mitgeführt.
SQL> select token_text from DR$MY_INDEX$I;
no rows selected

SQL> select token_text from DR$MY_INDEX$G;

TOKEN_TEXT
----------------------------------------------------------------
GEWINNT
HANSESTADT
IMMER
KRIMINALIT?T
NAHOST
PARTEI
STEIGT
TERROR
WAHL
WEITER

10 rows selected.
Um diese Tabelle in der SGA zu halten, kann man sich entweder auf das normale Caching Verhalten verlassen oder aber - falls konfiguriert - den KEEP Pool der Datenbank nutzen. Dazu kann man die folgenden Storage Attribute verwenden.
exec ctx_ddl.set_attribute ('my_storage', 'G_TABLE_CLAUSE', 
                                                  'storage (buffer_pool keep)');
exec ctx_ddl.set_attribute ('my_storage', 'G_INDEX_CLAUSE', 
                                                 'storage (buffer_pool keep)');
Möchte man nun die Daten in den Hauptindex manuell integrieren, kann man dazu das folgende OPTIMIZE Kommando verwenden.
execute ctx_ddl.optimize_index(idx_name=>'MY_INDEX', optlevel=>'MERGE');
Damit werden die Einträge aus $G in optimierter Form in die $I Tabelle überführt und gleichzeitig aus der $G Tabelle gelöscht.

Optimal wäre es nun, wenn dieser Aufgabe von Oracle automatisch durchgeführt werden könnte. Die neue Prozedur ADD_AUTO_OPTIMIZE erfüllt diese Aufgabe.
exec ctx_ddl.add_auto_optimize( 'my_index' )
PL/SQL procedure successfully completed.
Nach der Ausführung wird der Index zur automatischen Optimierung registriert, wie wir in der folgenden View sehen können.
SQL> select * from ctx_user_auto_optimize_indexes;

AOI_INDEX_NAME                 AOI_PARTITION_NAME
------------------------------ ------------------------------
MY_INDEX
Ausgeführt wird diese Aktion von einem DBMS_SCHEDULER Job, der automatisch im Hintergrund angelegt und ausgeführt wird.
SQL> select job_name, program_name, schedule_type, last_start_date 
     from dba_scheduler_jobs 
     where owner='CTXSYS';

JOB_NAME             PROGRAM_NAME         SCHEDULE_TYP
-------------------- -------------------- ------------
LAST_START_DATE
---------------------------------------------------------------------------
DR$BGOPTJOB          DR$BGOPTPRG          IMMEDIATE
08-OCT-13 04.42.13.977418 PM EUROPE/VIENNA
Übrigens lässt sich dieses Konzept des "two-level" Index - auch nachträglich mit einem ALTER INDEX REBUILD Kommando zu einem bestehenden Index hinzufügen.
alter index my_index rebuild parameters('replace storage my_storage');

Montag, 26. August 2013

Alle 12c Oracle Text Features auf einen Blick!

Mit der neuen Oracle Database 12c Version sind einige interessante neue Features im Oracle Text Umfeld implementiert worden. Nach und nach wollen wir diese in unseren deutschsprachigen Postings thematisieren.

Wer jetzt allerdings schon einen Überblick über alle neuen Text Features erhalten möchte, kann entweder im
Oracle Text Application Developer's Guide 12c Release 1 (12.1) im Abschnitt New Features recherchieren oder sich über das neue Whitepaper New Features in Oracle Text with Oracle Database12c informieren.

Viel Spaß dabei!

Beliebte Postings