Virtuelle Maschinen in zwei Rechenzentren organisieren (VMWare Pinning)

Virtuelle Maschinen in zwei Rechenzentren organisieren (VMWare Pinning)

Da wir im letzten Jahr unsere Infrastruktur um eine zweite Location in einem neuen Rechenzentrum erweitert haben, sind durch diesen Schritt neue Herausforderungen auf uns hinzugekommen.
Eine der Herausforderungen war, die Virtuellen Maschinen in den richtigen Rechenzentren laufen zu lassen.

Das heißt, dass die Virtuellen Maschinen (Config Files) sowie der Datastore am gleichen Standort läuft/liegt, um unnötigen Traffic über die Standleitungen zu verhindern.

Problembeschreibung:

Wir besitzen zwei VM-Farmen mit zugehörigen Storages, die auf zwei Rechenzentren aufgeteilt sind.

Wenn das Config File einer Virtuellen Maschine in Rechenzentrum 1 liegt, der Storage aber im Rechenzentrum 2, dann hat das natürlich extreme Auswirkungen auf das Netzwerk, da der Traffic immer zwischen den beiden Rechenzentren läuft.

Wenn die Virtuelle Maschine aber in einem Rechenzentrum läuft und die Storage auch korrekt definiert ist, dann ersparen wir uns den unnötigen Traffic.

Problemlösung:

Dazu habe ich ein Script entwickelt, dass das überprüft und die Ergebnisse unserem Monitoring System Zabbix meldet.

Ich habe für das Script Powershell verwendet.

Aufbau des Scripts:

  • Um in VMWare via Powershell Daten abzufragen oder Änderungen vornehmen zu können, muss man sich zuerst mit dem Server verbinden:
connect-viserver -Server <Server>
  • Abfrage der Config Files aller Virtuellen Maschinen in beiden Rechenzentren:
[string[]]$rzfmvms = Get-Cluster <Cluster1> | Get-VM | Select Name

[string[]]$zfs1config = Get-VM | Select Name, @{N="VMConfigFile";E={$_.extensiondata.config.files.vmpathname}} 
| Where VMConfigFile -Like "*<Storage1*>" | Select Name

[string[]]$zfs2config = Get-VM | Select Name, @{N="VMConfigFile";E={$_.extensiondata.config.files.vmpathname}} 
| Where VMConfigFile -Like "*<Storage2*>" | Select Name

[string[]]$rzesvms = Get-Cluster <Cluster2> | Get-VM | Select Name

[string[]]$zfs3config = Get-VM | Select Name, @{N="VMConfigFile";E={$_.extensiondata.config.files.vmpathname}} 
| Where VMConfigFile -Like "*<Storage3*>" | Select Name

[string[]]$zfs4config = Get-VM | Select Name, @{N="VMConfigFile";E={$_.extensiondata.config.files.vmpathname}} 
| Where VMConfigFile -Like "*<Storage4*>" | Select Name
[string[]]$zfsvms2 = $zfs3config + $zfs4config
  • Nach einigen notwendigen Zwischenschritten (hauptächlich Formatierungen: [@{Name=“, „“, } „“ entfernt) arbeite ich mit einer for-Schleife dann die Einträge ab und überprüfe, ob der Name der Virtuellen Maschine auf einem Storage eines anderen Rechenzentrum auftaucht und lese mir die „Persistent ID“ der Virtuellen Maschine aus.

Diese Information schicke ich dann an unser Monitoring System.

$<Cluster1> | ForEach-Object{
    
    $id = Get-VM | Where Name -Like $_ | select PersistentId
    C:\zabbix\ZABBIX_SENDER.EXE -z <ZabbixServerIP> -s $id.PersistentId -k <ZabbixTrigger> -o yes
}
#Send the information to Zabbix so we can monitor the wrong Config Files
$<Cluster2> | ForEach-Object{
    
    $id = Get-VM | Where Name -Like $_ | select PersistentId
    C:\zabbix\ZABBIX_SENDER.EXE -z <ZabbixServerIP> -s $id.PersistentId -k <ZabbixTrigger> -o yes
}

Somit kann ich über unser Monitoring System jederzeit überprüfen, welche Virtuellen Maschinen falsch laufen und diese dann entsprechend verschieben.

Anmerkung:

Mit der Version 5.0 von Zabbix kann man die Formatierung auch direkt im Preprocessing ohne JavaScript durchführen.

Oracle Statspack verbessern: Schnellere Snapshots – Teil1

Oracle Statspack verbessern: Schnellere Snapshots – Teil1

Ausgangslage: Langsamer Statspack Snapshot

Auf verschiedenen Standard Edition Datenbanken sieht man immer wieder den Statspack Snapshot lange laufen.

Dies ist für mich als Consultant sehr unangenehm.
Oft muss ich den Kunden sagen, dass das Statspack auf einer Standard Edition Datenbank unverzichtbar ist.

Und dann sieht mein Kunde, wie der Statspack Snapshot minutenlang einen der kostbaren, limitierten Cores blockiert.

Ich beschloss, etwas dagegen zu unternehmen.
Bei näherer Betrachtung erkennt man zwei Statements, die die Datenbank belasten.

In erster Linie ist dies:

INSERT INTO stats$sql_plan

Aber auch dieser Befehl läuft lange:

INSERT INTO stats$seg_stat

Grundsätzliches: Hints im Statspack

Man hört oft, dass man Hints so wenig wie möglich machen soll und lieber andere Mittel verwenden soll, um den Optimizer zu steuern.

Gute Statistiken zum Beispiel.
Ich bin auch dieser Meinung.
Allerdings gibt es auch Ausnahmen.

Bei Tools wie Statspack kann man sich nicht darauf verlassen, dass die Statistiken immer aktuell sind.

Es werden auch interne Tabellen X$ verwendet. Nicht jeder DBA macht fixed table stats und selbst wenn, schwanken diese Statistiken oft stark.

Ein Tool wie Statspack muss immer zuverlässig laufen.
Glücklicherweise ist bei den zwei Statspack Queries die wir betrachten werden, ziemlich klar wie der Plan auszusehen hat.

Hints stellen also kein großes Risiko dar. Jedoch habe ich dennoch so wenig wie möglich festgelegt.

Statement : INSERT INTO stats$sql_plan

Das Problem wird in der MOS Note 2182680.1 behandelt.

In dieser Note wird vorgeschlagen eine alternative Implementation des Statspack Package (SCPPKG.SQL) herunter zu laden und zu implementieren.

Diese Implementation enthält einen geänderten Hint, den ich im folgenden Beispiel mit Rot hervorgehoben habe.

Vom ganzen Insert Statement zeige ich nur den SELECT Teil, weil der Eintrag sonst zu lange wird.
Auch vom Select Teil habe ich die Liste der Spalten gekürzt, damit der Code Teil übersichtlich bleibt.

SELECT /*+ no_merge(new_plan) leading(new_plan s sp) use_nl(s) use_nl(sp) */
new_plan.plan_hash_value,
sp.id,
MAX(sp.operation),
MAX(sp.options), 
. . .
MAX(new_plan.snap_id)
FROM
(
SELECT /*+ index(spu) */
spu.plan_hash_value,
spu.hash_value hash_value,
spu.address address,
spu.text_subset text_subset,
spu.snap_id snap_id
FROM
stats$sql_plan_usage spu
WHERE
spu.snap_id = :b3
AND spu.dbid = :b2
AND spu.instance_number = :b1
AND NOT EXISTS (
SELECT /*+ nl_aj */
*
FROM
stats$sql_plan ssp
WHERE
ssp.plan_hash_value = spu.plan_hash_value
)
) new_plan,

Wie unschwer zu erkennen ist, befinden sie relevanten Suchkriterien auf der Tabelle stats$sql_plan_usage mit dem Alias spu.

Es ist also wichtig, dass im Execution Plan mit dem Lesen dieser Tabelle begonnen wird.

Der Hint Leading(new_plan .. ist also folgerichtig.

Das Problem besteht jedoch darin, dass new_plan keine Tabelle, sondern der Name einer Unterfrage ist.
Obwohl Version 19c den Hint als korrekt meldet, wird er in tieferen Versionen oft nicht akzeptiert.

Der Alias für den Hint wäre eigentlich spu, jedoch ist dieser in der Hauptabfrage nicht zugänglich, weil die Tabelle stats$sql_plan_usage in einer Unterabfrage angesprochen wird. (Achtung: wenn ein Alias vorhanden ist, muss der Alias im Hint angegeben werden und nicht der Tabelle Name.)

Diese Unterabfrage bildet einen eigenen Queryblock und dessen Inhalt ist von der Hauptabfrage nicht direkt referenzierbar.

In der Tat zeigt der Plan des Insert Befehles, dass der Leading Hint ignoriert wird.

Hier ein Beispiel von einem unserer Kunden:

Operation | Name | A-Time 
-------------------------------------------------------------------------------
INSERT STATEMENT | |00:05:07.72
LOAD TABLE CONVENTIONAL | STATS$SQL_PLAN |00:05:07.72
SORT GROUP BY | |00:05:07.72
NESTED LOOPS | |00:05:07.71
NESTED LOOPS | |00:05:07.71
FIXED TABLE FULL | X$KGLCURSOR_CHILD |00:00:02.30
VIEW PUSHED PREDICATE | |00:05:05.33
NESTED LOOPS ANTI | |00:05:05.23
TABLE ACCESS BY INDEX ROWID BATCHED| STATS$SQL_PLAN_USAGE |00:03:42.53
INDEX RANGE SCAN | STATS$SQL_PLAN_USAGE_PK|00:02:22.49
INDEX RANGE SCAN | STATS$SQL_PLAN_PK |00:01:03.19
FIXED TABLE FIXED INDEX | X$KQLFXPL (ind:3) |00:00:00.01
-------------------------------------------------------------------------------

Wie man sieht, benötigt der Insert 5 Minuten und 8 Sekunden.

Queryblöcke

Um eine Queryblock in der Hauptabfrage referenzieren zu können, muss man dem untergeordneten Queryblock mit dem QB_NAME hint einen Namen geben.

Dann kann man die Tabellen des untergeordneten Queryblocks mittels „tabellenalias@queryblock“ ansprechen.
Dies ist ein dokumentiertes Vorgehen und sollte in allen Versionen stabil funktionieren.

In unserem Beispiel sieht das so aus:

SELECT /*+ leading(spu@np ssp@sq s sp) */
new_plan.plan_hash_value,
sp.id,
...
MAX(new_plan.snap_id)
FROM
(
SELECT /*+ QB_NAME(NP) */
spu.plan_hash_value,
spu.hash_value hash_value,
spu.address address,
spu.text_subset text_subset,
spu.snap_id snap_id
FROM
stats$sql_plan_usage spu
WHERE
spu.snap_id = :b3
AND spu.dbid = :b2
AND spu.instance_number = :b1
AND NOT EXISTS (
SELECT /*+ QB_NAME(SQ) */
*
FROM
stats$sql_plan ssp
WHERE
ssp.plan_hash_value = spu.plan_hash_value
)
) new_plan,

Diesmal hält der Optimzer sich an die Hints, das Ergebnis sieht wie folgt aus:

--------------------------------------------------------------------------------
Operation | Name | A-Time
--------------------------------------------------------------------------------
INSERT STATEMENT | |00:00:00.05
LOAD TABLE CONVENTIONAL | STATS$SQL_PLAN |00:00:00.05
SORT GROUP BY | |00:00:00.05
NESTED LOOPS | |00:00:00.05
NESTED LOOPS | |00:00:00.04
HASH JOIN ANTI | |00:00:00.04
TABLE ACCESS BY INDEX ROWID BATCHED| STATS$SQL_PLAN_USAGE |00:00:00.01
INDEX RANGE SCAN | STATS$SQL_PLAN_USAGE_PK |00:00:00.01
INDEX FAST FULL SCAN | STATS$SQL_PLAN_PK |00:00:00.01
FIXED TABLE FIXED INDEX | X$KGLCURSOR_CHILD (ind:1)|00:00:00.01
FIXED TABLE FIXED INDEX | X$KQLFXPL (ind:3) |00:00:00.01
--------------------------------------------------------------------------------

Also 5 hundertstel Sekunden statt 5 Minuten.

Das ist über 6000x schneller und kann sich sehen lassen.

Nachdem ich die Hints gefunden hatte, habe ich eine Sicherheitskopie des Scriptes SCPPKG.SQL angelegt und den neuen Hint in das Package kopiert.
Durch den Aufruf des Scriptes wurde das neue Package dann installiert.

Statement: INSERT INTO stats$seg_stat

Wie sieht nun das zweite Insert aus?

Diesmal gibt es keine MOS Note.

Auch hier zeige ich wieder den sql code, mit den hervorgehobenen Hints:

SELECT /*+ ordered use_nl(s1.gv$segstat.X$KSOLSFTS) */
:b3,
:b2,
...
SUM(decode(s1.statistic_name, 'row lock waits', value, 0))
FROM
v$segstat s1
WHERE
( s1.dataobj#,
s1.obj#,
s1.ts# ) IN (
SELECT /*+ unnest */
s2.dataobj#,
s2.obj#,
s2.ts#
FROM
v$segstat s2
WHERE
s2.obj# > 0
AND s2.obj# < 4254950912
AND ( decode(s2.statistic_name, 'logical reads', s2.value, 0) > :b10
OR decode(s2.statistic_name, 'physical reads', s2.value, 0) > :b9
OR decode(s2.statistic_name, 'buffer busy waits', s2.value, 0) > :b8
OR decode(s2.statistic_name, 'row lock waits', s2.value, 0) > :b7
OR decode(s2.statistic_name, 'ITL waits', s2.value, 0) > :b6
OR decode(s2.statistic_name, 'gc cr blocks received', s2.value, 0) > :b5
OR decode(s2.statistic_name, 'gc current blocks received', s2.value, 0) > :b4 )
)
GROUP BY
s1.ts#,
s1.obj#,
s1.dataobj#
;

Wieder sieht man hier ein sehr ungewöhnliches Hint Format.

Wieder meldet aber die Report Funktion in 19c keinen Fehler und in unseren Test hat der Optimizer den Hint befolgt.

Jedoch bin ich diesmal mit der Wirkung des Hints nicht einverstanden.

Sehen wir uns dazu Laufzeitstatitiken an:

------------------------------------------------------------------------------
Id | Operation | Name | Starts | A-Rows | A-Time
------------------------------------------------------------------------------
0 | INSERT STATEMENT | | 1 | 0 |00:01:16.83
1 | LOAD TABLE CONVENTIONAL | STATS$SEG_STAT| 1 | 0 |00:01:16.83
2 | HASH GROUP BY | | 1 | 746 |00:01:16.83
3 | NESTED LOOPS | | 1 | 19396 |00:01:16.81
4 | VIEW | VW_NSO_1 | 1 | 747 |00:00:00.19
5 | SORT UNIQUE | | 1 | 747 |00:00:00.19
6 | FIXED TABLE FULL | X$KSOLSFTS | 1 | 814 |00:00:00.19
7 | FIXED TABLE FULL | X$KSOLSFTS | 747 | 19396 |00:01:16.62
------------------------------------------------------------------------------

Immerhin läuft auch dieser Befehl noch über eine Minute.

Die Zeit fällt fast zu 100% in der Zeile 7 an und zwar deshalb, weil die Zeile 747 Mal wiederholt wird.

Ein Hash join wäre hier wesentlich Laufzeit stabiler.
Der Nested Loop join hat Vorteile bei kleinen Datenmengen.

Allerdings spielt es ohnehin keine Rolle, welchen Join man nimmt, bei kleinen Datenmengen sind alle schnell.

Ich habe also den use_nl hint gegen einen use_hash hint getauscht.

Das ist das Resultat:

-------------------------------------------------------------------------------
Id | Operation | Name | Starts | A-Rows | A-Time
-------------------------------------------------------------------------------
0 | INSERT STATEMENT | | 1 | 0 |00:00:00.39
1 | LOAD TABLE CONVENTIONAL | STATS$SEG_STAT | 1 | 0 |00:00:00.39
2 | HASH GROUP BY | | 1 | 748 |00:00:00.39
3 | HASH JOIN | | 1 | 19448 |00:00:00.38
4 | VIEW | VW_NSO_1 | 1 | 748 |00:00:00.19
5 | SORT UNIQUE | | 1 | 748 |00:00:00.19
6 | FIXED TABLE FULL | X$KSOLSFTS | 1 | 815 |00:00:00.19
7 | FIXED TABLE FULL | X$KSOLSFTS | 1 | 390K|00:00:00.13
-------------------------------------------------------------------------------

Insgesamt läuft der Snapshot jetzt in 6 Sekunden durch.

Oracle APEX Ein Stolperstein im Upgrade auf Version 5.1

Oracle APEX: Ein Stolperstein im Upgrade auf Version 5.1

Beim Upgrade von Oracle APEX Applikationen auf die schon etwas ältere Version 5.1 wird gerne ein kleines Detail übersehen – vor allem auch deswegen weil die Auswirkungen nur dann sichtbar sind, wenn man alte und neue Version wirklich genau testet und vergleicht oder alternativ die Release Notes aufmerksam liest:

Im Abschnitt 1.4.4 der Release Notes befindet sich der Absatz:

End Date Displayed Inclusive — In release 5.0, the CSS calendar considered the end date of an all-day event as exclusive (similar to the jQuery FullCalendar Plugin).
In release 5.1, the end date is inclusive like all other Oracle Application Express components.

Das bedeutet, dass für die korrekte Darstellung eines mehrtägigen Termins in einer Calendar-Region in Version 5.0 folgende Abfrage notwendig war:

SELECT 'SomeCSSClass'         AS cal_class,
       t1.appointment_start   AS cal_date_from,
       t1.appointment_end + 1 AS cal_date_upto,
       'SomeLabel'            AS cal_label,
       'SomeLink'             AS cal_link
FROM   appointment_table t1

Mit dem Upgrade auf 5.1 entfällt die Notwendigkeit für das un-intuitive „+ 1“ und die Abfrage reduziert sich auf:

SELECT 'SomeCSSClass'         AS cal_class,
       t1.appointment_start   AS cal_date_from,
       t1.appointment_end     AS cal_date_upto,
       'SomeLabel'            AS cal_label,
       'SomeLink'             AS cal_link
FROM   appointment_table t1

Vor allem beim Überspringen von Applikations-Versionen kommt es dann mitunter vor, dass die Zwischenschritte ein wenig stiefmütterlich behandelt werden und sich Probleme wie dieses einschleichen.

Daher bietet es sich bei Oracle APEX Upgrades immer an, noch einmal einen kurzen Blick in die entsprechenden Release Notes zu werfen.

Long Parse aufgrund von Skew Detection in Hybrid Hash Distribution

Für einen detaillierten Überblick wie Skew Detection/Skew Handling in Hybrid Hash Distributionen funktioniert und welche Ziele es verfolgt, empfehle ich den sehr guten Blogeintrag von Randolf Geist zu lesen: https://oracle-randolf.blogspot.com/2014/05/12c-hybrid-hash-distribution-with-skew.html

Im Blog von Herrn Geist werden unter anderem sieben Vorbedingungen genannt, die nötig sind, damit dieses Feature wirksam wird.

Zumindest in Oracle 12.2 konnte ich auf Basis meiner Untersuchung eine weitere Vorbedingung finden:
Dynamic Sampling muss ebenfalls aktiviert sein (d.h auf einem Level > 0 konfiguriert sein; der Default ist 2).

Die rekursive Query die während der Optimierungsphase (=Hard Parse) ausgeführt wird, um einen Skew zu erkennen sieht nun auch ein wenig anders aus.

Zum Großteil wurden hier weitere Hints hinzugefügt.
Auf Oracle 12.2 hat sie nun folgende Form:

--kkopqSkewInfo: Query:SELECT /* DS_SKEW */ /*+ RESULT_CACHE no_parallel dynamic_sampling(0) no_sql_tune no_monitoring */ * FROM (SELECT SYS_OP_COMBINED_HASH("ID"), COUNT(*) CNT, TO_CHAR("ID") FROM "ASC_SKEW_PART" SAMPLE(99.900000) SEED(1) GROUP BY "ID" ORDER BY CNT DESC, "ID") WHERE ROWNUM <= 2;

Was hier sofort auffällt ist die Größe des gewählten Samples (99.9%).

Nach ein paar Tests mit unterschiedlichen Tabellengrößen, kam ich zum Schluss, dass das Sample so gewählt wird, um ca. 5.500 Rows aus der Tabelle zu selektieren, um auf dieser Datenbasis die Skew Erkennung durchzuführen.

Die Beschränkung auf 5.500 Rows wurde in älteren Releases schon vorgenommen, wenn Histogramme im Zuge der Statistikberechnung erzeugt wurden. Für Tabellen die weniger als 5.500 Rows haben, wird das Sample mit 99,9% gewählt.

Sehen wir uns nun an unter welchen Umständen das zu sehr langen Parse Zeiten führen kann:

--#######################################
--# Small lookup table                  #
--#######################################
drop table asc_pids;
create table asc_pids
as
select 45e6 + rownum id
  from dual
 connect by level <= 13;
 
--#######################################
--# Big, partitioned fact table         #
--#######################################
--5 mio records in each partition from P1 to P9
--only 4 records in partition P10
drop table asc_skew_part;
create table asc_skew_part
nologging
partition by range(id)
(
   partition P1 values less than (5e6),
   partition P2 values less than (10e6),
   partition P3 values less than (15e6),
   partition P4 values less than (20e6),
   partition P5 values less than (25e6),
   partition P6 values less than (30e6),
   partition P7 values less than (35e6),
   partition P8 values less than (40e6),
   partition P9 values less than (45e6),
   partition P10 values less than (50e6)
)
as
with a as
(
    select rownum id
      from dual
     connect by level <= 1e5
)
select /*+ parallel(4) */rownum id, 
       lpad('*', 255, '*') padding
  from a, a
 where rownum <= 45e6
union all
select 45e6 + mod(rownum, 2) + 1 id,
       lpad('*', 255, '*') padding
  from dual
 connect by level <= 4;
 
--#######################################
--# histograms on id on fact table      #
--####################################### 
exec dbms_stats.gather_table_stats(user, 'asc_skew_part', method_opt=>'for all columns size 1 for columns id size 255', granularity=>'ALL');


--#######################################
--# clear RC                            #
--#######################################
exec dbms_result_cache.flush();

Ich habe eine große, partitionierte Faktentabelle erstellt. Darin befinden sich jeweils 5 Millionen Rows in den Partitionen P1 bis P9 und nur 4 Rows in der letzten Partition P10 (2 Rows pro Value, das reicht um die notwendige Vorbedingung für die Skew Erkennung zu erfüllen).

Nachdem ich Histogramme auf der Faktentabelle erzeugt und den Result Cache (aufgrund des Hints in der rekursiven Query) geflushed habe, joine ich diese Tabelle nun zur kleinen Lookup-Tabelle.
Dabei schränke ich in der where Klausel aber so ein, dass nur Datensätze der kleinen Partition P10 selektiert werden.

--#######################################
--# note the long parsing time          #
--#######################################
explain plan for
select /*+ leading(b a) use_hash(a) parallel(8) pq_distribute(a HASH HASH)*/*
  from asc_skew_part a, asc_pids b
 where a.id = b.id
   and a.id between 45000000 and 50000000;

Die rekursive Query die im 10053 Event/Optimizer Trace ersichtlich ist, ist exakt jene die ich schon zu Beginn des Posts gezeigt habe:

--kkopqSkewInfo: Query:SELECT /* DS_SKEW */ /*+ RESULT_CACHE no_parallel dynamic_sampling(0) no_sql_tune no_monitoring */ * FROM (SELECT SYS_OP_COMBINED_HASH("ID"), COUNT(*) CNT, TO_CHAR("ID") FROM "ASC_SKEW_PART" SAMPLE(99.900000) SEED(1) GROUP BY "ID" ORDER BY CNT DESC, "ID") WHERE ROWNUM <= 2;

Hier wurde während des Parsens ein 99,9% Sample über alle Partitionen in einer Tabelle mit 45 Millionen Rows gelesen, eine Hash Funktion auf der Join Spalte angewandt und aggregiert.

Es sieht so aus als wäre die Größe des Samples nur von der kleinen Partition P10 (4 Rows) abgeleitet worden, die ich mit meiner where Klausel treffe.

Angewandt wurde das Sampling dann aber über die gesamte Tabelle, eine where Klausel um auf die entsprechende Partition zu filtern gibt es in der rekursiven Query nicht.

Im konkreten Fall ist das auf einer Produktions-DB mit Milliarden von Rows und hunderten Partitionen aufgetreten, woraufhin das bl0ße Parsen über Stunden gedauert hat.

Update: 

Offensichtlich wird die Anzahl der Zeilen, die der Optimizer nach Anwendung der Filter in der where Klausel schätzt, als Basis für die Größe des Samples herangezogen.

Wenn wir eine Tabelle mit 1 Mrd. Rows hätten, dabei ein Wert besonders oft vorkommen würde (≥30% defaultmäßig) und die anderen eindeutig wären, würde ein Filter auf einen der eindeutigen Werte zu einem Sample von 99,9% in der rekursiven Query führen (da der CBO 1 Row nach dem Filter schätzen würde; 1 ≤ 5,500 deswegen → 99,9%).

Natürlich müssen alle anderen Vorbedingungen (Histogramme, Hash Join, etc.) natürlich weiterhin erfüllt sein.

Um eine Zeile aus einer Tabelle von 1 Mrd. Rows zu lesen, möchte man es wahrscheinlich vermeiden 99,9% aller Rows während des Parsens zu lesen und zu aggregieren 😉

Beispiel:

create table asc_skew
nologging
as
with generator as
(
   select *
     from dual
    connect by level <= 1e4
)
select (case when mod(rownum, 2) = 0 then -1 else rownum end)            
       id, 
       rpad('*', 255, '*') padding
  from generator, generator
 where rownum <= 50e6;

create table asc_pids
as
select rownum id
  from dual
 connect by level <= 13;

exec dbms_stats.gather_table_stats(user, 'asc_skew', method_opt=>'for all columns size 1 for columns id size 255', granularity=>'ALL');

--this will parse very long
explain plan for
select /*+ leading(b a) use_hash(a) parallel(8) pq_distribute(a HASH HASH)  */*
  from asc_skew a, asc_pids b
 where a.id = b.id
   and a.id = 42;

Fazit:

Meiner Meinung nach sollte die Auswahl des Samples angepasst werden auf die Größe des Segments vor der Anwendung der where Klausel.

Weiters sollte auf partitionierte Tabellen besonders Rücksicht genommen werden.

Eventuell wäre es auch sinnvoll bei 99,9% komplett auf die sample Klausel zu verzichten, da diese z.B auch Smart Scans auf Exadata verhindert.

 

Cloud Control installation in silent mode made EASY

Cloud Control installation in silent mode made EASY

Step-by-Step guide how to install Oracle Cloud Control in silent mode the EASY way

Step1. Prepare machine configuration

Machine configuration (small setup of CC)
operation system: oracle linux 7
RAM 15GB
CPU 4
Storage 150GB  (OMS 125g+ archive destination 25g)

Stage the software somewhere on server.

[root@server1 software]#
[root@server1 software]# ls -ltr
total 4840584
-rw-r--r-- 1 root root 3059705302 Mar 10 14:46 LINUX.X64_193000_db_home.zip
-rw-r--r-- 1 root root  115653541 Mar 10 14:46 p6880880_190000_Linux-x86-64.zip
-rw-r--r-- 1 root root  773493643 Mar 10 14:50 p30125133_190000_Linux-x86-64.zip
-rw-r--r-- 1 root root  993959385 Mar 10 14:56 p30557433_190000_Linux-x86-64.zip
[root@server1 software]# pwd
/admin/software

Kernel parameter settings can be done via installting rpm from yum repository. (Kernelparameter with 19c + oracle base parameters by oracle-preinstall*19c )

As prerequisites preinstall package for oracle 19c was installaed from yum public repository.

Step 2. Now install database software and create the database

mkdir -p /u01/app/oracle/product/19.0.0/dbhome_1
                mkdir -p /u01/oradata
                chown -R oracle:oinstall /u01
                chmod -R 775 /u01

cd $ORACLE_HOME
unzip -oq /path/to/software/LINUX.X64_193000_db_home.zip

export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH:$ORACLE_HOME/OPatch

Here I installed the database software in silent mode without responsefile.

Reference doc is (Doc ID 885643.1) from oracle support.

Once it is completed then database was created in silent mode using dbca

————————————————————————————————————

Here are the steps

Prepare CCREPO database for cloud control installation (Here CCREPO is my database used for cloud control repository )

dbca -silent -responsefile NO_VALUE -createDatabase -gdbname 'CCREPO' -templateName General_Purpose.dbc  -databaseConfigType 'SI' -sysPassword 'XYZPQR' -systemPassword 'XYZPQR' -sampleSchema false -emConfiguration NONE  -storageType FS  -datafileDestination /u01/oradata -recoveryAreaDestination /u01/fra  -characterSet 'AL32UTF8'  -nationalCharacterSet 'AL16UTF16' -createAsContainerDatabase 'FALSE'  -initParams 'db_unique_name=CCREPO'

Logs

[root@server1 ]$ ./dbca -silent -responsefile NO_VALUE -createDatabase -gdbname 'CCREPO' -templateName General_Purpose.dbc  -databaseConfigType 'SI' -sysPassword 'XYZPQR' -systemPassword 'XYZPQR' -sampleSchema false -emConfiguration NONE  -storageType FS  -datafileDestination /u01/oradata -recoveryAreaDestination /u01/fra  -characterSet 'AL32UTF8'  -nationalCharacterSet 'AL16UTF16' -createAsContainerDatabase 'FALSE'  -initParams 'db_unique_name=CCREPO'
[WARNING] [DBT-06208] The 'SYS' password entered does not conform to the Oracle recommended standards.
  CAUSE:
Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9].b.The password entered is a keyword that Oracle does not recommend to be used as password
  ACTION: Specify a strong password. If required refer Oracle documentation for guidelines.
[WARNING] [DBT-06208] The 'SYSTEM' password entered does not conform to the Oracle recommended standards.
   CAUSE:
Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9].
b.The password entered is a keyword that Oracle does not recommend to be used as password
  ACTION: Specify a strong password. If required refer Oracle documentation for guidelines.
Prepare for db operation
10% complete
Copying database files
40% complete
Creating and starting Oracle instance
42% complete
46% complete
50% complete
54% complete
60% complete
Completing Database Creation
66% complete
69% complete
70% complete
Executing Post Configuration Actions
100% complete
Database creation complete. For details check the logfiles at:
 /u01/app/oracle/cfgtoollogs/dbca/CCREPO.
Database Information:
Global Database Name:CCREPO
System Identifier(SID):CCREPO
Look at the log file "/u01/app/oracle/cfgtoollogs/dbca/CCREPO/CCREPO.log" for further details.
[root@server1 ]$

Step3. Prepare the database CCREPO for Cloud control reposity

 

[root@server1 ]$ ps -ef|grep pmon
oracle   22723     1  0 Mar13 ?        00:00:10 ora_pmon_CCREPO
oracle   88030  4260  0 09:23 pts/0    00:00:00 grep --color=auto pmon
[root@server1 ]$ . oraenv
ORACLE_SID = [oracle] ? CCREPO
The Oracle base has been set to /u01/app/oracle
[root@server1 ]$ echo $ORACLE_SID
CCREPO
[root@server1 ]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Mon Mar 16 09:23:29 2020
Version 19.6.0.0.0
Copyright (c) 1982, 2019, Oracle.  All rights reserved.

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.6.0.0.0

SQL> select name,open_mode from v$database;

NAME      OPEN_MODE
--------- --------------------
CCREPO    READ WRITE

SQL> show parameter optimizer_adaptive_features;
SQL> show parameter adaptive; (All adaptive features parameters should be unset for improved SQL performance)

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_adaptive_plans             boolean     TRUE
optimizer_adaptive_reporting_only    boolean     FALSE
optimizer_adaptive_statistics        boolean     FALSE
parallel_adaptive_multi_user         boolean     FALSE
SQL> alter system set optimizer_adaptive_plans=FALSE scope=both;
System altered.
SQL> show parameter adaptive;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_adaptive_plans             boolean     FALSE
optimizer_adaptive_reporting_only    boolean     FALSE
optimizer_adaptive_statistics        boolean     FALSE
parallel_adaptive_multi_user         boolean     FALSE
SQL>

SQL> show parameter _allow_insert_with_update_check;
SQL> alter system set "_allow_insert_with_update_check"=true scope=both;
System altered.

SQL> show parameter _allow_insert_with_update_check;

NAME                                 TYPE        VALUE
----------------------------------- ----------- ------------------------------
_allow_insert_with_update_check      boolean     TRUE

SQL> ALTER  DATABASE tempfile 1 resize 5G;
Database altered.

SQL> select file_id,file_name,bytes/1024/1024/1024,maxbytes/1024/1024/1024,autoextensible from dba_temp_files where tablespace_name='TEMP' order by file_name;

   FILE_ID FILE_NAME                                          BYTES/1024/1024/1024 MAXBYTES/1024/1024/1024 AUT
---------- -------------------------------------------------- -------------------- ----------------------- ---
         1 /u01/oradata/CCREPO/temp01.dbf                                        5              31.9999847 YES

SQL> ALTER system SET session_cached_cursors = 400 scope = spfile;
SQL> ALTER system SET shared_pool_size = 1G scope = BOTH ;
SQL> ALTER system reset streams_pool_size scope = BOTH;
SQL> show parameter sga;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
allow_group_access_to_sga            boolean     FALSE
lock_sga                             boolean     FALSE
pre_page_sga                         boolean     TRUE
sga_max_size                         big integer 9632M
sga_min_size                         big integer 0
sga_target                           big integer 9632M
unified_audit_sga_queue_size         integer     1048576
SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_limit                  big integer 6402M
pga_aggregate_target                 big integer 3201M

SQL> show parameter process; (process should be at least 600 recommended)

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
aq_tm_processes                      integer     1
cell_offload_processing              boolean     TRUE
db_writer_processes                  integer     1
gcs_server_processes                 integer     0
global_txn_processes                 integer     1
job_queue_processes                  integer     160
log_archive_max_processes            integer     4
processes                            integer     640
processor_group_name                 string

alter system set "_optimizer_nlj_hj_adaptive_join"= FALSE scope=both sid='';
alter system set "_optimizer_strans_adaptive_pruning" = FALSE scope=both sid='';
alter system set "_px_adaptive_dist_method" = OFF scope=both sid='';
alter system set "_sql_plan_directive_mgmt_control" = 0 scope=both sid='';
alter system set "_optimizer_dsdir_usage_control" = 0 scope=both sid='';
alter system set "_optimizer_use_feedback" = FALSE scope=both sid='';
alter system set "_optimizer_gather_feedback" = FALSE scope=both sid='';
alter system set "_optimizer_performance_feedback" = OFF scope=both sid='';

SQL> shut immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup;
ORACLE instance started.

Total System Global Area 1.0100E+10 bytes
Fixed Size                 12445880 bytes
Variable Size            1543503872 bytes
Database Buffers         8522825728 bytes
Redo Buffers               21106688 bytes
Database mounted.
Database opened.

SQL> select name,open_mode from v$database;
NAME      OPEN_MODE
--------- --------------------
CCREPO    READ WRITE
SQL> exit

Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.6.0.0.0
[root@server1 ]$

Note: It is important to restart the CCREPO database after setting all these parameeters. After restart our database is ready to be a Cloud control repository now.

Step4. Cloud control Installation

create the directories
cd /u01/app/oracle
mkdir -p /u01/app/oracle/mw13             > ( This will be our OMS_HOME )
mkdir -p /u01/app/oracle/agent13         > ( This will be our AGENT_HOME )
mkdir -p /u01/app/oracle/gc_inst           > ( This will be our OMS instance )
mkdir -p /u01/app/oracle/swlib                               > ( This will be our Software library )
total 0

drwxrwxr-x  3 oracle oinstall  20 Mar 10 16:03 product
drwx------  2 oracle oinstall   6 Mar 10 16:55 checkpoints
drwxrwxr-x 23 oracle oinstall 280 Mar 10 16:55 diag
drwxr-x---  4 oracle oinstall  34 Mar 12 12:55 cfgtoollogs
drwxr-x---  4 oracle oinstall  33 Mar 13 15:50 admin
drwxr-x---  4 oracle oinstall  33 Mar 13 15:53 audit
drwx------  2 oracle oinstall   6 Mar 16 10:05 mw13
drwx------  2 oracle oinstall   6 Mar 16 10:05 agent13
drwx------  2 oracle oinstall   6 Mar 16 10:05 gc_inst
drwx------  2 oracle oinstall   6 Mar 16 10:05 swlib
[root@server1 ]$

Main steps — Enterprise manage cloud control 13.3 installation in silent mode

 

Reference Documentation link: https://docs.oracle.com/en/enterprise-manager/cloud-control/enterprise-manager-cloud-control/13.4/embsc/introduction.html#GUID-1F83B94D-EC8F-4ED7-B632-A3C1C593E6CD

Here is the list of rpms needed as per OMS,agent and middleware.

rpm required for OEM 13.4
-------------------------------
binutils-2.23.52.0.1
compat-libcap1-1.10
compat-libstdc++-33-3.2.3.x86_64
compat-libstdc++-33-3.2.3.i686
gcc-4.8.2
gcc-c++-4.8.2
glibc-2.17.x86_64
glibc-2.17.i686
glibc-devel-2.17.x86_64
libaio-0.3.109.x86_64
libaio-devel-0.3.109.x86_64
libgcc-4.8.2.x86_64
libgcc-4.8.2.i686
libstdc++-4.8.2.x86_64
libstdc++-4.8.2.i686
libstdc++-devel-4.8.2.x86_64
dejavu-serif-fonts
ksh
make-3.82
sysstat-10.1.5
numactl-2.0.9 for x86_641
numactl-devel-2.0.9 for x86_642
motif-2.3.4-7 for x86_643
motif-devel-2.3.4-7 for x86_644
redhat-lsb-4.1-27.0.1.el7 for x86_64
redhat-lsb-core-4.1-27.0.1.el7 for x86_64
OpenSSL 1.0.1e
make-3.82-21
binutils-2.23
gcc-4.8.2-16
libaio-0.3.109-12
glibc-common-2.17-55
libstdc++-4.8.2-16
sysstat-10.1.5-4

rpm -qa rpm_name (to check if installed or not)

Download and stage the software EM 13.4 to the destination server.

https://www.oracle.com/enterprise-manager/downloads/linux-x86-64-13c-rel4-downloads.html

Directions

Download all the files including .bin in same directory. No need to unzip the downloaded software.

As the install user who will be installing the product, set the execute permission for the .bin file. Example: chmod +x em13400_linux64.bin

Chanage permissions and scp the software on destination server.

chmod 755 em13400_linux64.bin em13400_linux64*

ls -ltr
total 17300064
-rwxr-xr-x 1 oracle oinstall 1623577684 Mar 16 12:22 em13400_linux64.bin
-rwxr-xr-x 1 oracle oinstall 2109004737 Mar 16 12:25 em13400_linux64-2.zip
-rwxr-xr-x 1 oracle oinstall 2047749474 Mar 16 12:28 em13400_linux64-3.zip
-rwxr-xr-x 1 oracle oinstall 2117312528 Mar 16 12:32 em13400_linux64-4.zip
-rwxr-xr-x 1 oracle oinstall  808014516 Mar 16 12:33 em13400_linux64-5.zip
-rwxr-xr-x 1 oracle oinstall 2143125187 Mar 16 12:36 em13400_linux64-6.zip
-rwxr-xr-x 1 oracle oinstall 1879163226 Mar 16 12:39 em13400_linux64-7.zip

Step4.1. Prepare responsefile for OEM

pwd
/u01/software
             mkdir responsefiles
             cd responsefiles

           pwd
                /u01/software/responsefiles

cd ..
pwd
/u01/software
[root@server1 ]$ ls -ltr
total 16501492

drwxr-xr-x 5 oracle oinstall         81 Jan  7 04:07 30557433
-rw-rw-r-- 1 oracle oinstall     237583 Jan 15 14:30 PatchSearch.xml
-rwxrwxr-x 1 oracle oinstall 3059705302 Mar 10 15:26 LINUX.X64_193000_db_home.zip
-rwxrwxr-x 1 oracle oinstall  993959385 Mar 10 15:27 p30557433_190000_Linux-x86-64.zip
-rwxrwxr-x 1 oracle oinstall  115653541 Mar 10 15:27 p6880880_190000_Linux-x86-64.zip
-rwxr-xr-x 1 oracle oinstall 2109004737 Mar 16 12:48 em13400_linux64-2.zip
-rwxr-xr-x 1 oracle oinstall 2047749474 Mar 16 12:48 em13400_linux64-3.zip
-rwxr-xr-x 1 oracle oinstall 2117312528 Mar 16 12:49 em13400_linux64-4.zip
-rwxr-xr-x 1 oracle oinstall  808014516 Mar 16 12:49 em13400_linux64-5.zip
-rwxr-xr-x 1 oracle oinstall 2143125187 Mar 16 12:49 em13400_linux64-6.zip
-rwxr-xr-x 1 oracle oinstall 1879163226 Mar 16 12:49 em13400_linux64-7.zip
-rwxr-xr-x 1 oracle oinstall 1623577684 Mar 16 12:50 em13400_linux64.bin
drwx------ 2 oracle oinstall          6 Mar 16 12:57 responsefiles

./em13400_linux64.bin -getResponseFileTemplates -outputLoc /u01/software/responsefiles

My responsefile creation command got failed here becauseIi had very less space in /temp

ERROR Details :
----------------
[root@server1 ]$ ./em13400_linux64.bin -getResponseFileTemplates -outputLoc /u01/software/responsefiles
ERROR: Temporary directory /tmp does not have enough free space. At least 12289 MB of free space are required.
Please input another directory or [Exit]: exit
ERROR: Cannot setup the extract directory /tmp/sfx_DRYjy1 (-1).

[root@server1 ]$ df -h /tmp
Filesystem                 Size  Used Avail Use% Mounted on
/dev/mapper/rootvg-tmp_lv  5.5G   44M  5.5G   1% /tmp
[root@server1 ]$

Note: Here I have very less space available in my temp file system. As per oracle support we need at least 14gb of temp.

https://docs.oracle.com/en/enterprise-manager/cloud-control/enterprise-manager-cloud-control/13.4/embsc/oracle-enterprise-manager-deployment-prerequisites.html#GUID-C72126D0-C99F-4348-8CCB-7C49FC2E4ED2

So here we have 2 options.

Either increase temp file system or use another file system for temp where you have enough recommended space. Here I use another file system for /tmp

In order to fix this I have used a workaround here by using my own created space for temp because

 

cd u01
mkdir temp
cd temp
pwd
/u01/temp

export TMP=/u01/temp
export TMPDIR=/u01/temp
export TEMP=/u01/temp

./em13400_linux64.bin -J-Djava.io.tmpdir=/u01/temp -getResponseFileTemplates -outputLoc /u01/software/responsefiles  (Reference oracle documentation (Doc ID 2308484.1) )
logs from above command.

--------------------------------------
[root@server1 ]$ export TMP=/u01/temp
[root@server1 ]$ export TMPDIR=/u01/temp
[root@server1 ]$ export TEMP=/u01/temp
[root@server1 ]$ echo $TMP
/u01/temp
[root@server1 ]$ echo $TMPDIR
/u01/temp
[root@server1 ]$ echo $TEMP
/u01/temp

[root@server1 ]$ ./em13400_linux64.bin -J-Djava.io.tmpdir=/u01/temp -getResponseFileTemplates -outputLoc /u01/software/responsefiles
Launcher log file is /u01/temp/OraInstall2020-03-19_11-10-25AM/launcher2020-03-19_11-10-25AM.log.
Extracting the installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Done
Copying response file template(s)
to /u01/software/responsefiles
  Copying response file template upgrade.rsp
  Copying response file template new_install.rsp
  Copying response file template software_only.rsp
Finished copying response file template(s)

The log(s) can be found here: /u01/temp/OraInstall2020-03-19_11-10-25AM.
[root@server1 ]$

Prepare the responsefile

cd responsefiles
ls -ltr
cp new_install.rsp myoem_install.rsp

Now edit this file myoem_install.rsp as below.

I removed all empty space and edit as per your requirement .

new edited responsefile (file location is /u01/software/responsefiles)

cat myoem_install_updated.rsp

INVENTORY_LOCATION="/u01/app/oraInventory"
SECURITY_UPDATES_VIA_MYORACLESUPPORT=false
DECLINE_SECURITY_UPDATES=true
INSTALL_UPDATES_SELECTION=skip
ORACLE_MIDDLEWARE_HOME_LOCATION="/u01/app/oracle/mw13"
AGENT_BASE_DIR="/u01/app/oracle/agent13"
ORACLE_HOSTNAME="server1.com"
WLS_ADMIN_SERVER_USERNAME="weblogic"
WLS_ADMIN_SERVER_PASSWORD="XYZPQR"
WLS_ADMIN_SERVER_CONFIRM_PASSWORD="XYZPQR"
NODE_MANAGER_PASSWORD="XYZPQR"
NODE_MANAGER_CONFIRM_PASSWORD="XYZPQR"
ORACLE_INSTANCE_HOME_LOCATION="/u01/app/oracle/gc_inst"
CONFIGURE_ORACLE_SOFTWARE_LIBRARY=true
SOFTWARE_LIBRARY_LOCATION="/u01/app/oracle/swlib"
DATABASE_HOSTNAME="server1.com"
LISTENER_PORT=1521
SERVICENAME_OR_SID="CCREPO"
SYS_PASSWORD="XYZPQR"
SYSMAN_PASSWORD="XYZPQR"
SYSMAN_CONFIRM_PASSWORD="XYZPQR"
DEPLOYMENT_SIZE=MEDIUM
MANAGEMENT_TABLESPACE_LOCATION="/u01/oradata/CCREPO/mgmt.dbf"
CONFIGURATION_DATA_TABLESPACE_LOCATION="/u01/oradata/CCREPO/mgmt_ecm_depot1.dbf"
JVM_DIAGNOSTICS_TABLESPACE_LOCATION="/u01/oradata/CCREPO/mgmt_deepdive.dbf"
AGENT_REGISTRATION_PASSWORD="XYZPQR"
AGENT_REGISTRATION_CONFIRM_PASSWORD="XYZPQR"
CONFIGURATION_TYPE=ADVANCED
CONFIGURE_SHARED_LOCATION_BIP=false
EM_INSTALL_TYPE=NOSEED

Step5: Install Cloud control in silent mode

cd software location for oem

cd /u01/software

./em13400_linux64.bin -silent -responseFile /u01/software/responsefiles/myoem_install_updated.rsp -J-Djava.io.tmpdir=/u01/temp

or

nohup ./em13400_linux64.bin -silent -responseFile /u01/software/responsefiles/myoem_install_updated.rsp -J-Djava.io.tmpdir=/u01/temp &

Logs

[root@server1 ]$ ./em13400_linux64.bin -silent -responseFile /u01/software/responsefiles/myoem_install_updated.rsp -J-Djava.io.tmpdir=/u01/temp
Launcher log file is /u01/temp/OraInstall2020-03-19_01-26-16PM/launcher2020-03-19_01-26-16PM.log.
Extracting the installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Done
Checking swap space: must be greater than 512 MB.   Actual 19455 MB    Passed
Checking if this platform requires a 64-bit JVM.   Actual 64    Passed (64-bit not required)
Preparing to launch the Oracle Universal Installer from /u01/temp/OraInstall2020-03-19_01-26-16PM

====Prereq Config Location main===
/u01/temp/OraInstall2020-03-19_01-26-16PM/stage/prereq
EMGCInstaller args -scratchPath
EMGCInstaller args /u01/temp/OraInstall2020-03-19_01-26-16PM
EMGCInstaller args -sourceType
EMGCInstaller args network
EMGCInstaller args -timestamp
EMGCInstaller args 2020-03-19_01-26-16PM
EMGCInstaller args -paramFile
EMGCInstaller args /u01/temp/sfx_dJv119/Disk1/install/linux64/oraparam.ini
EMGCInstaller args -silent
EMGCInstaller args -responseFile
EMGCInstaller args /u01/software/responsefiles/myoem_install_updated.rsp
EMGCInstaller args -nocleanUpOnExit
DiskLoc inside SourceLoc/u01/temp
EMFileLoc:/u01/temp/OraInstall2020-03-19_01-26-16PM/oui/em/
ScratchPathValue :/u01/temp/OraInstall2020-03-19_01-26-16PM
EMGCInstallUpdatesInfoOnNext:: calling actionOnClickofNext
Now in EMGCInstallUpdatesInfoOnNext.actionsOnClickofNext
EMGCInstallUpdatesInfoOnNext:: End of actionOnClickofNext
Oracle strongly recommends using the AL32UTF8 character set for EM repository. AL32UTF8 is Oracle's name for the standard Unicode encoding UTF-8, which enables universal support of virtually all languages of the world.

 The following prerequisite check failed because the Oracle Database, where the Management Repository will be configured, does not meet the configuration requirements. These failures do not impact the installation, but you may encounter performance issues with the product later. You can either click Cancel, fix the issue manually now, based on the recommendation offered for this prerequisite, and click Next, or you can click OK to fix it after the installation ends. For more details check the logs: /u01/temp/OraInstall2020-03-19_01-26-16PM/emdbprereqs
Prereq Name             Recommendation
Check the redo log size.                Redo Log file size should be 600000000 bytes or greater.  Generally, there should be 3 or more redo logs available of this size.
Session log file is /u01/temp/OraInstall2020-03-19_01-26-16PM/install2020-03-19_01-26-16PM.log
Installation in progress
Install successful
Linking in progress
Link successful
Setup in progress
Setup successful
Session log file is /u01/temp/OraInstall2020-03-19_01-26-16PM/install2020-03-19_01-26-16PM.log
Installation in progress
Install successful
Linking in progress
Link successful
Setup in progress
Setup successful
Agent OracleHome :/u01/app/oracle/agent13/agent_13.4.0.0.0
Session log file is /u01/temp/OraInstall2020-03-19_01-26-16PM/install2020-03-19_01-26-16PM.log
..................................................................................................
Installation in progress (Thursday, March 19, 2020 1:32:41 PM CET)
                              98% Done.
Install successful
Linking in progress (Thursday, March 19, 2020 1:32:42 PM CET)
Link successful
Setup in progress (Thursday, March 19, 2020 1:32:42 PM CET)
Setup successful
Saving inventory (Thursday, March 19, 2020 1:32:42 PM CET)
Saving inventory complete
End of install phases.(Thursday, March 19, 2020 1:32:47 PM CET)
Session log file is /u01/temp/OraInstall2020-03-19_01-26-16PM/install2020-03-19_01-26-16PM.log
...............................................................  18% Done.
...............................................................  37% Done.
...............................................................  56% Done.
...............................................................  75% Done.
...............................................................  94% Done.
...............

Installation in progress (Thursday, March 19, 2020 1:33:14 PM CET)
.
.
.
.
at the end
---------------
Use the following URL to access:
Enterprise Manager Cloud Control URL: https://server1.com:7803/em
Admin Server URL: https://server1.com:7102/console
BI Publisher URL: https://server1.com:9803/xmlpserver/servlet/home

The following details need to be provided while installing an additional OMS:
Admin Server Host Name: server1.com
Admin Server Port: 7102

You can find the details on ports used by this deployment at : /u01/app/oracle/mw13/install/portlist.ini
 NOTE:
 An encryption key has been generated to encrypt sensitive data in the Management Repository. If this key is lost, all encrypted data in the Repository becomes unusable.
 A backup of the OMS configuration is available in /u01/app/oracle/gc_inst/em/EMGC_OMS1/sysman/backup on host server1.com. See Cloud Control Administrators Guide for details on how to back up and recover an OMS.

 NOTE: This backup is valid only for the initial OMS configuration. For example, it will not reflect plug-ins installed later, topology changes like the addition of a load balancer, or changes to other properties made using emctl or emcli. Backups should be created on a regular basis to ensure they capture the current OMS configuration. Use the following command to backup the OMS configuration:
/u01/app/oracle/mw13/bin/emctl exportconfig oms -dir <backup dir>

Prompt for the allroot.sh

Warning: You must run the following configuration scripts as the "root" user.
  /u01/app/oracle/mw13/allroot.sh
To execute the configuration scripts:
Open a new terminal window.
Login in as "root".
Run the scripts.
Successfully installed Enterprise Manager Cloud Control.
Logs successfully copied to /u01/app/oraInventory/logs.
[root@server1 ]$

Step 7. Check the status of OEM

Status of OMS

[root@server1 ]$ /u01/app/oracle/mw13/bin/emctl status oms
Oracle Enterprise Manager Cloud Control 13c Release 4
Copyright (c) 1996, 2020 Oracle Corporation.  All rights reserved.
WebTier is Up
Oracle Management Server is Up
JVMD Engine is Up
BI Publisher Server is Up

Status of agent

[root@server1 ]$ pwd
/u01/app/oracle/agent13/agent_13.4.0.0.0/bin
[root@server1 ]$ ./emctl status agent

Oracle Enterprise Manager Cloud Control 13c Release 4
Copyright (c) 1996, 2020 Oracle Corporation.  All rights reserved.
---------------------------------------------------------------
Agent Version          : 13.4.0.0.0
OMS Version            : 13.4.0.0.0
Protocol Version       : 12.1.0.1.0
Agent Home             : /u01/app/oracle/agent13/agent_inst
Agent Log Directory    : /u01/app/oracle/agent13/agent_inst/sysman/log
Agent Binaries         : /u01/app/oracle/agent13/agent_13.4.0.0.0
Core JAR Location      : /u01/app/oracle/agent13/agent_13.4.0.0.0/jlib
Agent Process ID       : 1492
Parent Process ID      : 1425
Agent URL              : https://server1.com:3872/emd/main/
Local Agent URL in NAT : https://server1.com:3872/emd/main/
Repository URL         : https://server1.com:4903/empbs/upload
Started at             : 2020-03-19 15:04:41
Started by user        : oracle
Operating System       : Linux version 3.10.0-1062.9.1.el7.x86_64 (amd64)
Number of Targets      : 53
Last Reload            : (none)
Last successful upload                       : 2020-03-19 15:49:43
Last attempted upload                        : 2020-03-19 15:49:43
Total Megabytes of XML files uploaded so far : 2.31
Number of XML files pending upload           : 0
Size of XML files pending upload(MB)         : 0
Available disk space on upload filesystem    : 67.07%
Collection Status                            : Collections enabled
Heartbeat Status                             : Ok
Last attempted heartbeat to OMS              : 2020-03-19 15:51:46
Last successful heartbeat to OMS             : 2020-03-19 15:51:46
Next scheduled heartbeat to OMS              : 2020-03-19 15:52:46
---------------------------------------------------------------
Agent is Running and Ready
[root@server1 ]$

 

Business Continuity Management

Business Continuity Management

Wir verfügen über einen Business Continuity Plan sowie ein aktives Krisenmanagement, um auf Krisensituationen reagieren zu können und den Fortgang unserer Geschäftstätigkeiten stets sicherzustellen.

Unsere IT Infrastruktur zur Überwachung aller Kunden-Systeme ist über zwei professionelle Rechenzentren in unterschiedlichen Wiener Bezirken gespiegelt.

Alle Mitarbeiter nutzen einen virtuellen Desktop via Citrix. Das bedeutet, dass jeder Mitarbeiter mit seinem Laptop über eine verschlüsselte Verbindung von überall arbeiten kann, wo eine Internet Verbindung oder ein mobiles Netz zur Verfügung steht.

Meetings untereinander, sowie mit Kunden und Lieferanten können auch über Video-Konferenz Tools abgehalten werden.

Wir möchten hiermit unsere Kunden, Partner und Lieferanten über unseren aktuellen Umgang mit der aktuellen Situation zum COVID-19 Ausbruch informieren.

Unsere aktuell gültige Sicherheitsstufe seit 02.06.2020:

Hinweis

Sicherheitsstufe 2

Sicherheitsstufe 1

Normalbetrieb, keine Einschränkungen. Es gelten die allgemeinen Regeln bezüglich Anwesenheit und Homeoffice.

Sicherheitsstufe 2

Eingeschränkter Vorortbetrieb mit Standard Hygieneregeln.

  • Mitarbeiter/innen arbeiten nach Abstimmung teilweise in unseren Büroräumlichkeiten.
    Dabei ist zu beachten, dass zumindest 50% der Techniker Belegschaft im Homeoffice arbeitet und jedes Büro mit maximal 2 gegenübersitzenden Personen mit getrennten Schreibtischen besetzt ist.
  • Termine beim Kunden Vorort und der Empfang von Kunden oder Lieferanten im Büro können stattfinden.
  • Beim Abhalten von Meetings in Besprechungsräumen muss zwischen den Teilnehmern mindestens ein Sessel Abstand eingehalten werden.
  • Die Durchführung von Besprechungen im Arbeitsplatzbereich ist nicht erlaubt.
  • Bei Personenansammlungen in den öffentlichen Bereichen (Sozialbereich, Küche, Gänge) ist darauf zu achten, dass der Mindestabstand von einem Meter zwischen Personen jedenfalls eingehalten wird.
  • Bei Bildung von Fahrgemeinschaften gelten die aktuell gültigen Bestimmungen der Regierung.
  • Auf der hauseigenen IT Produktions-Infrastruktur dürfen kritische Wartungsarbeiten nur mit Genehmigung durchgeführt werden.

Sicherheitsstufe 3

Eingeschränkter Vorortbetrieb mit verschärften Hygieneregeln.

  • Mitarbeiter/innen können, sofern nicht explizit angeordnet, auf freiwilliger Basis und vorab geplant in den Büroräumlichkeiten arbeiten. Dabei ist zu beachten, dass zumindest 50% der Techniker Belegschaft weiterhin im Homeoffice arbeitet und jedes Büro mit maximal 2 gegenübersitzenden Personen mit getrennten Schreibtischen besetzt ist.
  • Termine beim Kunden Vorort und der Empfang von Kunden oder Lieferanten im Büro können unter den verschärften Hygieneregeln stattfinden.
  • Für das Abhalten von Meetings sind Videokonferenzen vorzuziehen.
  • Beim Abhalten von Meetings in Besprechungsräumen muss zwischen den Teilnehmern mindestens ein Sessel Abstand eingehalten werden. Es gilt eine Maximalbelegung von 40% der möglichen Kapazität. Masken müssen bei Meetings mit ausreichendem Abstand (min. 1 Meter) nicht getragen werden.
  • Besprechungen am Arbeitsplatz mit zimmerfremden Personen ist nicht erlaubt.
  • Führungspersonal und deren Stellvertreter sollen nicht gleichzeitig Vorort anwesend sein.
  • Personenansammlungen von mehr als 4 Personen in öffentlichen Bereichen sind zu vermeiden.
  • Bei Bildung von Fahrgemeinschaften gelten die verschärften Hygieneregeln.
  • Auf der hauseigenen IT Produktions-Infrastruktur dürfen kritische Wartungsarbeiten nur mit Genehmigung durchgeführt werden.

Sicherheitsstufe 4

Der Vorort-Betrieb beschränkt sich auf eine/n Frontoffice Mitarbeiter/in zur Entgegennahme von Postsendungen und Lieferungen.

  • Alle anderen Mitarbeiter/innen arbeiten über Remotezugang aus dem koordinierten Homeoffice.
  • Meetings zwischen Mitarbeitern und Kunden oder Lieferanten werden ausnahmslos online über Videokonferenz Tools abgehalten.
  • Es finden keine physischen Besuche von Kunden und Lieferanten, weder bei Kunden oder Lieferanten Vorort noch im Büro statt.
  • Für den/die Vorort-Mitarbeiter/in gelten bei der Entgegennahme von Postsendungen oder Liefergegenstände die verschärften Hygieneregeln.
  • Auf der hauseigenen IT Produktions-Infrastruktur dürfen nur unbedingt notwendigen Wartungsarbeiten mit ausdrücklicher Genehmigung durchgeführt werden, um die Verfügbarkeit der Systeme nicht zu gefährden.

Standard Hygieneregeln

Zu unseren Standard Hygieneregeln zählen:

  • Die Hände nach dem Betreten der Büroräumlichkeiten beim Empfang desinfizieren.
  • Regelmäßig die Hände mit Seife waschen oder mit Desinfektionsmittel desinfizieren.
  • Das Gesicht und vor allem den Mund, die Augen und die Nase nicht mit den Fingern berühren.
  • Händeschütteln und Umarmungen unbedingt vermeiden.
  • Niesen und Husten in die Armbeugen oder in ein Papiertaschentuch und dieses sofort entsorgen.
  • Die Räume regelmäßig (wenn möglich quer-) lüften, wenn möglich einmal pro Stunde
  • Bei Anzeichen von Krankheit zu Hause bleiben und soziale Kontakte vermeiden.
  • Mindestens 1 Meter Abstand zu den Mitmenschen einhalten.

Verschärfte Hygieneregeln

Zu unseren verschärften Hygieneregeln zählen alle Standard Hygieneregeln, sowie:

  • In allen öffentlichen Bereichen der Büroflächen (Empfangsbereich, Gänge, Küche, WC, Sozialbereiche, etc., …) ist stets eine Mund-Nasenmaske oder eine abdeckende mechanische Schutzvorrichtung zu tragen.
  • Bei Vorort Kundenterminen ist zu beachten, dass die verschärften Hygieneregeln auch beim Kunden eingehalten werden können.

 

Wir beobachten und bewerten laufend die Situation und leiten entsprechende Handlungen daraus ab. Gemeinsam schaffen wir auch die COVID-19 Herausforderung zu meistern.

Homeworking Arbeitsplätze der Mitarbeiter

Vergleich der Oracle SQL Funktionen ADD_MONTHS vs INTERVAL

Oracle SQL ADD_MONTHS vs. INVERVAL Funktionen

ADD_MONTHS:

Die Funktion ADD_MONTHS fügt einem Datum eine definierte Anzahl von Monaten hinzu.

Die Syntax sieht folgendermaßen aus:

ADD_MONTHS (input_date, number_months)

Um diese Operation durchführen zu können, werden also zwei verpflichtende Parameter benötigt:

Input_date: Datum, zu welchem n Monate dazugerechnet werden

Number_months: Anzahl der Monate vom Datentyp Integer, die zum angegebenen Datum dazugerechnet werden.

Der Rückgabewert dieser Funktion ist immer ein DATE.

SELECT ADD_MONTHS (‚17-04-2020‘, 2) AS ADD_MONTHS_RESULT
FROM DUAL

 

Ist das angegebene Datum der letzte Tag des Monats und das resultierende Datum hat weniger oder mehr Tage, so ist das Ergebnis der letzte Tag des Monats.

SELECT ADD_MONTHS (‚31-03-2020‘, 1) AS ADD_MONTHS_RESULT
FROM DUAL

Natürlich kann man vom angegebenen Datum auch Monate abziehen, indem man ein „–“ vor den Monaten platziert.

SELECT ADD_MONTHS (‚28-02-2020‘, -1) AS ADD_MONTHS_RESULT
FROM DUAL

Spannend wird das Thema bei Schaltjahren.
2020 ist ein Schaltjahr, somit hat der Februar 29 anstatt 28 Tage.

SELECT ADD_MONTHS (‚28-02-2020‘, 1) AS ADD_MONTHS_RESULT
FROM DUAL

Nimmt man jedoch den 29. Februar, so bekommt man nicht den 29. März als Resultat, sondern den 31. März.

SELECT ADD_MONTHS (‚29-02-2020‘, 1) AS ADD_MONTHS_RESULT 
FROM DUAL

INTERVAL YEAR TO MONTH:

Dies ist ein spezieller Datentyp, welcher es ermöglicht, Intervalle von Jahren und Monaten zu speichern.

Die Syntax hat folgendes Format:

INTERVAL ‚year[-month]‘ [YEAR[(precision)])] [TO MONTH]

Defaultmäßig wird precision auf 2 gesetzt, sofern nichts anderes angegeben wurde. Das heißt, es können nur 99 Jahre und 11 Monate gespeichert werden.

INTERVAL '120-3' YEAR(3) TO MONTH:

Intervall von 120 Jahren und 3 Monaten.

In diesem Fall muss precision angegeben werden, da die angegebenen Jahre dreistellig sind.

INTERVAL '105' YEAR(3)

Intervall von 105 Jahren.

INTERVAL '500' MONTH(3)

Intervall von 500 Monaten.

In diesem Fall muss precision angegeben werden, da die angegebenen Monate dreistellig sind.

Bei Monatsangaben muss man sehr genau sein.

Anders als bei ADD_MONTHS rechnet INTERVAL nicht automatisch auf den letzten Tag des Monats.

Folgendes Statement gibt einen „ORA-01839: Datum für angegebenen Monat nicht gültig“ Fehler zurück:

SELECT TO_DATE (‚31-01-2020‘) + INTERVAL ‚1‘ MONTH AS RESULT
FROM DUAL

Auch bei Schaltjahren muss man sehr genau sein.

Dieses Statement gibt einen „ORA-01839: Datum für angegebenen Monat nicht gültig“ Fehler zurück:

SELECT TO_DATE (‚29-02-2020‘) + INTERVAL ‚3‘ YEAR AS RESULT 
FROM DUAL

Korrekt wäre:

SELECT TO_DATE (‚29-02-2020‘) + INTERVAL ‚4‘ YEAR AS RESULT FROM DUAL


 

Oracle Session Killer

Oracle Standard Edition – Simple Session/SQL Killer

In diesem kurzen Blog Post zeigen wir, wie man mittels einer einfachen Prozedur „long running Sessions“ killen kann.

Der Nachteil dieser Lösung ist, dass die komplette Session gekillt wird.

Damit diese Lösung aber so generisch wie möglich ist, werden nur jene Spalten selektiert die ausreichen, um eine Identifikation des USER/SQL sicherzustellen.

Es ist natürlich möglich, auch weitere Spalten hinzuzugeben und die Tabellen Definition dafür anzupassen.

Diese Killer Prozedur eignet sich für Oracle Standard Edition Datenbanken, wo kein Resource Manager funktioniert.

Ab Version 18c hat Oracle eine „CANCEL SQL“ eingeführt, siehe https://oracle-base.com/articles/18c/alter-system-cancel-sql-18c

Wenn Sie eine höhere Version verwenden, kann diese Prozedur einfach umgeschrieben werden, in dem Sie folgendes Statement …

stmt := 'alter system kill session '''|| d.sid ||','||d.serial#||',@'||d.inst_id||''' immediate';

auf…

stmt := 'alter system cancel sql '''|| d.sid ||','||d.serial#||',@'||d.inst_id||''' ';

…ändern.

PLSQL Code

drop table sys.dbmonitor_tab purge ;
create table sys.dbmonitor_tab (datum timestamp, inst_id number, sid number, serial# number, username varchar2(50), sql_id varchar2(30), sql_text varchar2(50)) tablespace users ;

create or replace procedure sys.dbmonitor(timeout IN number) IS 
-- query everything what is NOT a background process, bg processes dont have a username :)
cursor get_data is select s.inst_id, s.sid, s.serial#, s.username, s.sql_id, substr(sql.sql_text,1,50) as txt from gv$session s, gv$sqlarea sql where s.sql_id=sql.sql_id and s.inst_id=sql.inst_id and 
status='ACTIVE' and round(last_call_et / 60,2) > timeout and username is not null ;
d get_data%rowtype;
stmt varchar2(4000) ;
begin
for d in get_data
loop 
-- audit the query
insert into sys.dbmonitor_tab values (systimestamp, d.inst_id, d.sid, d.serial#, d.username, d.sql_id, d.txt) ;
commit ;

stmt := 'alter system kill session '''|| d.sid ||','||d.serial#||',@'||d.inst_id||''' immediate';
-- kill it!
execute immediate stmt ;
end loop;

exception
when others then
NULL ;
end; 
/

Test Szenario

Session 1: (läuft normalerweise sehr lange):

SQL> select count(*) from dba_objects,dba_objects,dba_objects ;

Session 2: (kill session die länger als 1 Minute laufen):

SQL> exec dbmonitor(1)

PL/SQL procedure successfully completed.

SQL> select * from sys.dbmonitor_tab ;

DATUM INST_ID SID SERIAL# USERNAME SQL_ID SQL_TEXT
---------------------------------------- ---------- ---------- ---------- ---------- ------------------------------ --------------------------------------------------
15-MAY-20 01.39.37.429586 PM 1 85 60201 SYS d3s7r4a3xa0su select count(*) from dba_objects,dba_objects,dba_o
15-MAY-20 01.43.00.013776 PM 1 85 59874 SYS d3s7r4a3xa0su select count(*) from dba_objects,dba_objects,dba_o

Session 1 bekommt folgende Meldung angezeigt:

SQL> select count(*) from dba_objects,dba_objects,dba_objects ;
select count(*) from dba_objects,dba_objects,dba_objects
*
ERROR at line 1:
ORA-00028: your session has been killed

Wenn Oracle 18c oder eine höhere Versionen implementiert ist, bekommt die Session folgenden Error angezeigt und wird nicht gekillt.

Der Benutzer kann in diesem Fall weiterarbeiten.

SQL> select count(*) from dba_objects,dba_objects,dba_objects ;
select count(*) from dba_objects,dba_objects,dba_objects
*
ERROR at line 1:
ORA-01013: user requested cancel of current operation

Um diese Prozedur autonom zu machen, können wir in der Datenbank einen Scheduler Job erstellen, der alle 5 Minute gestartet wird und jene Sessions killt, die länger als 5 Minuten laufen:

begin
dbms_scheduler.create_job(
job_name=>'SYS.SESSION_KILLER',
job_type=>'PLSQL_BLOCK',
job_action=>'begin dbmonitor(5);end;',
repeat_interval=>'FREQ=MINUTELY;BYMINUTE=0,5,10,15,20,25,30,35,40,45,50,55',
enabled=>true);
end;
/
Dbvisit switchover under the hood

Dbvisit switchover under the hood

Dbvisit Standby is a complete physical standby solution for Oracle Standard Edition databases, where we can’t use Oracle Data Guard due to licensing restrictions.

Executing switchover in Dbvisit configuration is quite a straightforward process – just click on “Perform graceful switchover” and select the configuration where we want to execute the switchover.

Before performing switchover, ensure that daemons are turned off and log gap is 0.

DBVisit main screen

Dbvisit main screen

DBVisit switchover screen

Dbvisit switchover screen

But what’s happening on the databases during the switchover process?

Dbvisit provides us only very high-level information.

DBVisit switchover status

Dbvisit switchover status

 

But what’s going on during each step?

Let’s have a look: 

1.      Running pre-checks

In this step, network connectivity, database availability and running processes are checked.

2.      Pre processing

Nologging operations, log gap and standby consistency are checked.

3.      Processing primary

Database is restarted in restricted session mode, current log is archived and standby redolog files are created.

Then the database is restarted, control file is backed up by Dbvisit and the database is shut down.

4.      Processing standby, converting standby

The control file backup created in the previous step and all the missing redo logs are transferred to the standby location.

The standby DB is restarted with that control file to mount exclusive mode and the data files are renamed in the control file if necessary.

Online log files are dropped on the standby and unarchived online log files from the primary DB are transferred to recover the standby database. TEMP files are deleted from the control file.

Afterwards, the database is opened mode as the new primary DB – role transition was done by transferring the control file from the primary DB, therefore there’s no need to convert it. Now when the database is open, the missing online log files are recreated.

Converting standby is complete.

5.      Converting primary

Database is started to mount state, role switch is executed, online logs are deleted on OS and the database is restarted again to mount state. After the restart, the database role is PHYSICAL STANDBY.

6.      Completing

Missing temp files in the new primary are recreated.

7.      Synchronizing

All the new archived logs from the new primary are being transferred to the new standby.

8.      Post processing

Dbvisit configuration is updated and variables are reversed between primary and standby.

Oracle Text Troubleshooting

Oracle Text Index – Concept and troubleshooting its related issues

With Oracle text indexes (or Domain index), we can index text documents and search it based on contents using text patterns with specialized text query operators.

Oracle Text index is different from the traditional B-Tree or Bitmap indexes. They have several components communicates internally.

In a query application, the table must contain the text or pointers to where the text is stored. Text is usually a collection of documents but can also be small text.

Oracle Text index differs from the traditional B-Tree or Bitmap. In an Oracle Text index, the text data is not directly indexed rather, the text data is split into a set of tokens (these splits stored in database internal tables) and tokens are indexed.

Oracle Text Index objects

Oracle Text index has four tables: $I, $K, $N and $R tables.

The $I table contains the data which is being indexed, all the tokens (words) generated from the text document is stored in this table. The tokens in this table are indexed by a B-Tree index with name format DR${index_name}$X.

The $K table maps the internal DOCID values to external ROWID values (fetching a DOCID when we know the ROWID value) .

The $R table maps the ROWID values to DOCID values, (fetching a ROWID when we know the DOCID value). The entries from this table are indexed by a B-Tree index with name format DRC${index_name}$R.

The $N table contains a list of deleted DOCID values, which are cleaned up by the index optimization process.

Oracle Text Health Check

 Oracle Text Status and Version:

  1. A: Status of all CTXSYS objects status :
SELECT * FROM dba_objects
WHERE status !='VALID' AND OWNER = 'CTXSYS' 
ORDER BY object_type,     object_name;

B: The query for health check of the index.
The idx_docid_count is Number of documents indexed. The number of idx_docid_count should be the same or close to the number of rows of base table. The domidx_status  is domain index status.

SELECT c.idx_owner,c.idx_name,c.idx_text_name,c.idx_type,
c.idx_docid_count, i.status,i.domidx_status
FROM ctxsys.ctx_indexes c, dba_indexes i
WHERE c.idx_owner = ‘OWNER’
AND c.idx_name = ‘INDEX_NAME' and c.idx_name=i.index_name
ORDER BY 2,3;

C: Compilation errors of invalid Text-related objects:

SELECT owner, name, type, line, position, text
  FROM dba_errors
 WHERE owner = 'CTXSYS'
      OR (owner = 'SYS' AND (name like 'CTX_%' or name like 'DRI%'))
  ORDER BY owner, name, sequence;

  SELECT * FROM ctxsys.ctx_index_errors
   ORDER BY err_timestamp DESC, err_index_owner, err_index_name;

D: Extract the DDL of the existing index :

SELECT CTX_REPORT.CREATE_INDEX_SCRIPT('SCHEMA.INDEX_NAME') FROM DUAL;
  1. Validating the Index integrity:

A: Validate $K against the base table(there should be no rows selected for a valid INDEX) :

select  *
from dr$INDEX_NAME$k k
where not exists (select 1
from TABLE_NAME t
where k.textkey = t.rowid);

The keys on $K  table should be match with the base table rowids.

B: Validate $R against $K(there should be no rows selected for a valid INDEX) :

select  *
from table(ctx_diag.decode_r('dr$INDEX_NAME$R')) r
where not exists (select 1
from dr$INDEX_NAME$k k
where r.textkey = k.textkey);

C: validate $R (find duplicates) (there should be no rows selected for a valid INDEX) :

column docids for a40

select  textkey, listagg(docid, ', ') within group (order by docid) docids
from table(ctx_diag.decode_r('dr$INDEX_NAME$R'))
group by textkey
having count(*) > 1;

The above queries for validating the TEXT index should have no return values therefore the index would be consistence.

Types of Oracle Text Indexes

CONTEXT

Use this index to build a text retrieval application when your text consists of large coherent documents.

You can index documents of different formats such as MS Word, HTML or plain text.

You can customize the index in a variety of ways.

This index type requires CTX_DDL.SYNC_INDEX after DML on base table.

Note! Transactional CONTEXT Indexes: The new TRANSACTIONAL parameter to CREATE INDEX and ALTER INDEX enables changes to a base table to be immediately queryable.

CTXCAT

Use this index type for better mixed query performance.

Typically, with this index type, you index small documents or text fragments.
Other columns in the base table, such as item names, prices, and descriptions can be included in the index to improve mixed query performance.

This index is larger and takes longer to build than a CONTEXT index.

The size of a CTXCAT index is related to the total amount of text to be indexed, the number of indexes in the index set, and the number of columns indexed.
Consider your queries and your resources before adding indexes to the index set.

This index type is transactional, automatically updating itself after DML to base table.

No CTX_DDL.SYNC_INDEX is necessary.

CTXRULE

Use CTXRULE index to build a document classification or routing application.

This index is created on a table of queries, where the queries define the classification or routing criteria. 

ALTER INDEX Sync Methods

 MANUAL:

No automatic synchronization. This is the default. You must manually synchronize the index with CTX_DDL.SYNC_INDEX.

EVERY:

Automatically synchronize the index at a regular interval specified by the value of interval-string.

ON COMMIT:

Synchronize the index immediately after a commit.   

TRANSACTIONAL:

Specify that documents can be searched immediately after they are inserted or updated.

If a text index is created with TRANSACTIONAL enabled, then, in addition to processing the synchronized rowids already in the index, the CONTAINS operator will process unsynchronized rowids as well.

To turn on TRANSACTIONAL index property:

ALTER INDEX myidx REBUILD PARAMETERS('replace metadata transactional');
                To turn off TRANSACTIONAL index property:
ALTER INDEX myidx REBUILD PARAMETERS('replace metadata nontransactional');

Oracle Text Index preferences

DATASTORE:

  1.  DIRECT_DATASTORE: Indicates that the data is stored internally in text columns of a database table.
  2. MULTI_COLUMN_DATASTORE: Indicates that the data is stored in text table in more than one column. Columns are concatenated (joined) to create a virtual document and each concatenated row is indexed as a single document
  3. DETAIL_DATASTORE: Indicates that the data is stored internally in a text column.
  4. NESTED_DATASTORE: Indicates that the data is stored in nested tables
  5. FILE_DATASTORE: Indicates that the data is stored in Operating System files. This type of data source is supported only for CONTEXT index.
  6. URL_DATASTORE: Indicates that the data is stored over Internet.
  7. USER_DATASTORE: Indicates that the documents would be synthesized at index time by a user defined stored procedure

FILTER:

In this phase the text stream can be converted to format that is recognized by the Oracle text processing engine. 

SECTIONER:

 The task of the sectioner is to divide the incoming text stream into multiple sections based on the internal document structures (HTML or XML).

 LEXER:

This property determines the language associated with the incoming document.

 How to SYNC_INDEX after DML on base table

The following script is useful to synchronize the index with the base table when using context type of text index:

export ORACLE_SID=SID_NAME
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/ctx/lib:$ORACLE_HOME/lib32:/usr/lib
sqlplus "/as sysdba" << EOF
exec ctx_ddl.sync_index(idx_name =>'SCHEMA.INXEX’);
exit;
EOF