Oracle Statspack verbessern: Historische Pläne – Teil 2

Grundlegendes: Ändern des Statspack Code

English version here : Improving Statspack: Add Support for Plan Stability

Natürlich sollte man den Statspack Code nicht leichtfertig ändern. Das wird Niemand wollen. Die hier besprochene Änderung erlaubt es, schnell und ohne großes Nachdenken einen Plan aus der Vergangenheit wieder her zu stellen.

Für manche Applikationen und Datenkonstellationen ist diese Möglichkeit wirklich wichtig.
In diesem Fall sollte man es sich gründlich überlegen, ob man die hier beschriebene Veränderung nicht doch machen will.

Schließlich hat man den Source Code des Statspack. Man sollte die originale Codeversion behalten und kann daher jederzeit den Originalcode schnell wiederherstellen. Die zusätzliche optionale Spalte stört da nicht.

Ausgangslage

Bei meinem Webinar „The good plan and the bad Plan” für die DOAG ging es darum, gute Pläne aus der Vergangenheit wieder zu aktivieren.

Kann man die AWR Daten lesen, so kann man beispielsweise aus den DBA_HIST Daten mittels dbms_xplan.display_awr ein Outline erzeugen. Dieses Outline kann man dann in aktuelle Pläne einpflanzen.

Ich wurde damals gefragt, ob eine solche Methode auch auf einer Oracle Standard Edition Datenbank funktioniert.

Mit dem SQL_PATCH [2] gibt es eine legale Möglichkeit, ein Outline in einen SQL Befehl einzupflanzen.

Die Frage ist nur, wie man auf einer Oracle Standard Edition zu einem Outline eines alten Planes kommt.
Gibt es mit Statspack eine Funktion ähnlich dem dbms_xplan.display_awr?

Uwe Küchler, alias Oraculix hat eine sehr kreative Lösung parat [1].

Man verwendet einfach dbms_xplan.display im Zusammenhang mit einer Suchfunktion:

select * from table(dbms_xplan.display(
  table_name   => 'perfstat.stats$sql_plan',
  statement_id => null,
  format       => 'ALL -predicate -note',
  filter_preds => 'plan_hash_value = '|| &&phv
);

Man muss dazu noch eine Spalte in der Tabelle stats$sql_plan ergänzen, die Einzelheiten finden Sie im Oraculix Blog.

Was passiert nun, wenn man jetzt einfach im Format noch +OUTLINE angibt?
Dann müsste man doch das Outline bekommen. Da könnte man dann über einen SQL_PATCH in ein Statement schreiben und voila, hat man den alten Plan zurück.

Oder etwa nicht?

Nein, die Format Anweisung wird scheinbar einfach ignoriert.
Der Grund hierfür ist, dass in den Statspack Plänen einige Spalten fehlen. Konkret geht es hier um die Spalte OTHER_XML, die nicht mitgespeichert wird.

Die Spalte other_xml

In dieser Spalte findet sich unter anderen das Outline. Wer also die sehr wichtige Funktion der historischen Pläne haben will, darf nicht davor zurückscheuen, den Statspack code zu verändern. Wenn Oracle schon die der MOS Note 2182680.1 vorschlägt das Statspack zu verändern, weshalb sollte wir nicht ein wenig weiter gehen?

Wir beginnen, in dem wir die Spalte hinzufügen.

ALTER TABLE perfstat.stats$sql_plan ADD timestamp INVISIBLE AS (cast(NULL AS DATE));
ALTER TABLE perfstat.stats$sql_plan ADD OTHER_XML CLOB;

Danach müssen wir den Code anpassen. Analog zum Vorgehen in MOS Note 2182680.1 habe ich zuerst eine Kopie des aktuellen Codes gemacht.
Wieder ist es das Skript spcpkg, welches angepasst werden muss.

Zu ändern ist das Insert Statement beginnend mit:

insert into stats$sql_plan
                 ( plan_hash_value
                 , id
                 , operation
                 , options
                 , object_node
                 , object#

Hier muss die Spalte Other_XML ergänzt werden. Dabei gibt es jedoch eine Schwierigkeit.

Im Select Teil des Inserts steht eine Maximum Funktion, z.B. so:

                 , max(sp.operation)
                 , max(sp.options)
                 , max(sp.object_node)
                 , max(sp.object#)
                 , max(sp.object_owner)
                 , max(sp.object_name)
                 , max(sp.object_alias)
                 , max(sp.object_type)

Die Maximum Funktion ist ziemlich sicher nur dafür da, um duplizierte Sätze zu vermeiden.

Also schreiben wir doch einfach: Max(other_xml), oder?

Prompt kommt ORA-00932. Der Grund dafür ist, dass CLOB nicht sortierbar sind, daher kann auch kein Maximum berechnet werden.

ANY_VALUE

Natürlich gäbe es noch andere Möglichkeiten, um die Werteliste eindeutig zu machen.
Beispielsweise analytische Funktionen wie row_number ().

Ich wolle jedoch nicht so viel am Original Code verändern.

Mir fiel eine Idee aus dem Oracle Technologie Network ein, bei der es darum ging, für genau solche Probleme eine neue Art von Gruppenfunktion ein zu führen, genannt ANY_VALUE [3.].

Die Idee wird anscheinend mit Version 20c umgesetzt. Zu schade. Mit Version 19 wäre besser.

Als ehemaliger Oracle Mitarbeiter weiß ich jedoch, dass manchmal die Vorgängerversionen undokumentiert schon Änderungen der Folgeversion enthalten.

Und in der Tat: any_value gibt es schon.
Leider wirft auch diese Implementation völlig unnötig ORA-00932.

Ich habe Chris Saxon darauf aufmerksam gemacht und hoffe das Oracle die Implementierung noch ändert.
Nun, wenn Oracle nicht liefert muss ich das selbst machen.

Ich habe mir über das User-Defined Aggregate Functions Interface die Funktion selbst definiert und any_lob genannt.

Den Code finden sie am Ende dieses Blogs. Hier erst einmal der vollständige Insert Befehl. Die alle vom Standard abweichenden Änderungen sind mit Rot gekennzeichnet. Die Hints habe ich im vorigen Blog zum Thema Statspack beschrieben.

            insert into stats$sql_plan
                 ( plan_hash_value
                 , id
                 , operation
                 , options
                 , object_node
                 , object#
                 , object_owner
                 , object_name
                 , object_alias
                 , object_type
                 , optimizer
                 , parent_id
                 , depth
                 , position
                 , search_columns
                 , cost
                 , cardinality
                 , bytes
                 , other_tag
                 , partition_start
                 , partition_stop
                 , partition_id
                 , other
                 , other_xml                 
                 , distribution
                 , cpu_cost
                 , io_cost
                 , temp_space
                 , access_predicates
                 , filter_predicates
                 , projection
                 , time
                 , qblock_name
                 , remarks
                 , snap_id
                 )
            select /*+ leading(spu@np ssp@sq  s sp) */
                   new_plan.plan_hash_value
                 , sp.id
                 , max(sp.operation)
                 , max(sp.options)
                 , max(sp.object_node)
                 , max(sp.object#)
                 , max(sp.object_owner)
                 , max(sp.object_name)
                 , max(sp.object_alias)
                 , max(sp.object_type)
                 , max(sp.optimizer)
                 , max(sp.parent_id)
                 , max(sp.depth)
                 , max(sp.position)
                 , max(sp.search_columns)
                 , max(sp.cost)
                 , max(sp.cardinality)
                 , max(sp.bytes)
                 , max(sp.other_tag)
                 , max(sp.partition_start)
                 , max(sp.partition_stop)
                 , max(sp.partition_id)
                 , max(sp.other)
                 , any_lob(sp.other_xml)
                 , max(sp.distribution)
                 , max(sp.cpu_cost)
                 , max(sp.io_cost)
                 , max(sp.temp_space)
                 , 0 -- should be max(sp.access_predicates) (2254299)
                 , 0 -- should be max(sp.filter_predicates)
                 , max(sp.projection)
                 , max(sp.time)
                 , max(sp.qblock_name)
                 , max(sp.remarks)
                 , 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         = l_snap_id
                       and spu.dbid            = p_dbid
                       and spu.instance_number = p_instance_number
                       and not exists (select /*+ QB_NAME(SQ)  */ *
                                         from stats$sql_plan ssp
                                        where ssp.plan_hash_value 
                                            = spu.plan_hash_value
                                      )
                   )          new_plan
                 , v$sql      s      -- join reqd to filter already known plans
                 , v$sql_plan sp
             where s.address         = new_plan.address
               and s.plan_hash_value = new_plan.plan_hash_value
               and s.hash_value      = new_plan.hash_value
               and sp.hash_value     = new_plan.hash_value
               and sp.address        = new_plan.address
               and sp.hash_value     = s.hash_value
               and sp.address        = s.address
               and sp.child_number   = s.child_number
             group by 
                   new_plan.plan_hash_value, sp.id
             order by
                   new_plan.plan_hash_value, sp.id; -- deadlock avoidance

Zusammenfassung

Der Code scheint recht gut zu funktionieren.

Nur eine Sache war etwas ärgerlich: Immer, wenn ich Syntaxfehler im Insert hatte, musste ich auch die Funktion any_lob neu kompilieren.

Hinweis: Man muss den Snap Level auf 6 oder höher schalten, damit das Statspack Pläne sammelt.  Z.B.:

EXECUTE statspack.snap(i_snap_level => 7);

Create or replace type any_lob_type as object
(
  v_clob CLOB,

  static function ODCIAggregateInitialize
    ( sctx in out any_lob_type )
    return number ,

  member function ODCIAggregateIterate
    ( self  in out any_lob_type ,
      value in     CLOB
    ) return number ,

  member function ODCIAggregateTerminate
    ( self        in  any_lob_type,
      returnvalue out CLOB,
      flags in number
    ) return number ,

  member function ODCIAggregateMerge
    ( self in out any_lob_type,
      ctx2 in     any_lob_type
    ) return number
);
/

create or replace type body any_lob_type
is
  static function ODCIAggregateInitialize
  ( sctx in out any_lob_type )
  return number
  is
  begin
    sctx := any_lob_type( null ) ;
    return ODCIConst.Success ;
  end;

  member function ODCIAggregateIterate
  ( self  in out any_lob_type ,
    value in     CLOB
  ) return number
  is
  begin
    self.v_clob := value ;
    return ODCIConst.Success;
  end;

  member function ODCIAggregateTerminate
  ( self        in  any_lob_type ,
    returnvalue out CLOB ,
    flags       in  number
  ) return number
  is
  begin
    returnvalue := self.v_clob;
    return ODCIConst.Success;
  end;

  member function ODCIAggregateMerge
  ( self in out any_lob_type ,
    ctx2 in     any_lob_type
  ) return number
  is
  begin
      return ODCIConst.Success;
  end;
end;
/

create or replace function any_lob
  ( input CLOB )
  return CLOB
  deterministic
  parallel_enable
  aggregate using any_lob_type
;
grant execute on any_lob to public;
create public sysnonym for sys.any_lob;

Quellen

 

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 ]$

 

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;
/
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
Kill Blocking Job entfernt Blocking Sessions

Kill-Blocker-Job erkennt und entfernt Blocking-Sessions

Der Kill-Blocker-Job dient dazu, um Blocking-Sessions in der Oracle Datenbank zu erkennen und eventuell existierende „Blocker“ zu identifizieren und per E-Mail zu melden.

Dabei kann festgelegt werden, in welchen Intervallen die Blocking-Sessions gemeldet werden und ob sie automatisch gekillt werden oder nicht.

In diesem Beispiel wurde definiert, dass alle Blocking-Sessions die länger als 30 Sekunden blockieren, automatisch identifiziert werden und per E-Mail an mehrere eMail Adressen gemeldet werden.

Weiters versucht der Kill-Blocker-Job die Blocker-Sessions automatisch zu killen.

1) Tablespace BLOCKMON erstellen

Für den neuen User BLOCKMON kann optional ein Tablespace erstellt werden. In unserem Fall erstellen wir einen neuen Tablespace.

create tablespace BLOCKMON datafile size 100M autoextend on maxsize 5G;

2) User BLOCKMON erstellen

create user BLOCKMON identified by PASSWORDDEFINIEREN default tablespace BLOCKMON;

Dem User BLOCKMON müssen folgende, notwendige Rechte vergeben werden:

GRANT CREATE SESSION TO BLOCKMON;
GRANT SELECT ANY DICTIONARY TO BLOCKMON;
GRANT CREATE PROCEDURE,CREATE SEQUENCE,CREATE VIEW,CREATE TABLE TO BLOCKMON;
ALTER USER BLOCKMON QUOTA UNLIMITED ON USERS;
GRANT "RESOURCE" TO BLOCKMON ;
ALTER USER BLOCKMON DEFAULT ROLE "RESOURCE";
GRANT CREATE JOB TO BLOCKMON ;
GRANT ALTER SYSTEM TO BLOCKMON ;
GRANT UNLIMITED TABLESPACE TO BLOCKMON ;

3) Tabellen als User BLOCKMON erstellen

Als nächster Schritt müssen folgende Tabellen erstellt werden.
In diesen Tabellen werden die Details zu den Blockern gespeichert – wie zum Beispiel die Kill-Logdaten und Lock-Logdaten.

3-1- DDL für die Tabelle KILLLOG

CREATE TABLE "BLOCKMON"."KILLLOG" 
   (    "SNAP" NUMBER, 
    "TS" TIMESTAMP (6), 
    "INST_ID" NUMBER, 
    "SID" NUMBER, 
    "STMT" VARCHAR2(4000 BYTE)
   ) 
  TABLESPACE "BLOCKMON" ;

3-2- DDL für die Tabelle LOCKLOG

  CREATE TABLE "BLOCKMON"."LOCKLOG" 
   (    "INST_ID" NUMBER, 
    "ADDR" RAW(8), 
    "KADDR" RAW(8), 
    "SID" NUMBER, 
    "TYPE" VARCHAR2(2 BYTE), 
    "ID1" NUMBER, 
    "ID2" NUMBER, 
    "LMODE" NUMBER, 
    "REQUEST" NUMBER, 
    "CTIME" NUMBER, 
    "BLOCK" NUMBER, 
    "SNAP" NUMBER, 
    "TS" TIMESTAMP (6)
   ) 
  TABLESPACE "BLOCKMON" ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu Problem kommen, dass einige Spalten fehlen. Daher muss in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen werden und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table locklog;
create table locklog as (select s.*,1 snap,sysTIMESTAMP ts from gv$lock s where 1=0);

3-3- DDL für die Tabelle SESSIONLOG

  CREATE TABLE "BLOCKMON"."SESSIONLOG" 
   (    "INST_ID" NUMBER, 
    "SADDR" RAW(8), 
    "SID" NUMBER, 
    "SERIAL#" NUMBER, 
    "AUDSID" NUMBER, 
    "PADDR" RAW(8), 
    "USER#" NUMBER, 
    "USERNAME" VARCHAR2(30 BYTE), 
    "COMMAND" NUMBER, 
    "OWNERID" NUMBER, 
    "TADDR" VARCHAR2(16 BYTE), 
    "LOCKWAIT" VARCHAR2(16 BYTE), 
    "STATUS" VARCHAR2(8 BYTE), 
    "SERVER" VARCHAR2(9 BYTE), 
    "SCHEMA#" NUMBER, 
    "SCHEMANAME" VARCHAR2(30 BYTE), 
    "OSUSER" VARCHAR2(30 BYTE), 
    "PROCESS" VARCHAR2(24 BYTE), 
    "MACHINE" VARCHAR2(64 BYTE), 
    "PORT" NUMBER, 
    "TERMINAL" VARCHAR2(30 BYTE), 
    "PROGRAM" VARCHAR2(48 BYTE), 
    "TYPE" VARCHAR2(10 BYTE), 
    "SQL_ADDRESS" RAW(8), 
    "SQL_HASH_VALUE" NUMBER, 
    "SQL_ID" VARCHAR2(13 BYTE), 
    "SQL_CHILD_NUMBER" NUMBER, 
    "SQL_EXEC_START" DATE, 
    "SQL_EXEC_ID" NUMBER, 
    "PREV_SQL_ADDR" RAW(8), 
    "PREV_HASH_VALUE" NUMBER, 
    "PREV_SQL_ID" VARCHAR2(13 BYTE), 
    "PREV_CHILD_NUMBER" NUMBER, 
    "PREV_EXEC_START" DATE, 
    "PREV_EXEC_ID" NUMBER, 
    "PLSQL_ENTRY_OBJECT_ID" NUMBER, 
    "PLSQL_ENTRY_SUBPROGRAM_ID" NUMBER, 
    "PLSQL_OBJECT_ID" NUMBER, 
    "PLSQL_SUBPROGRAM_ID" NUMBER, 
    "MODULE" VARCHAR2(64 BYTE), 
    "MODULE_HASH" NUMBER, 
    "ACTION" VARCHAR2(64 BYTE), 
    "ACTION_HASH" NUMBER, 
    "CLIENT_INFO" VARCHAR2(64 BYTE), 
    "FIXED_TABLE_SEQUENCE" NUMBER, 
    "ROW_WAIT_OBJ#" NUMBER, 
    "ROW_WAIT_FILE#" NUMBER, 
    "ROW_WAIT_BLOCK#" NUMBER, 
    "ROW_WAIT_ROW#" NUMBER, 
    "TOP_LEVEL_CALL#" NUMBER, 
    "LOGON_TIME" DATE, 
    "LAST_CALL_ET" NUMBER, 
    "PDML_ENABLED" VARCHAR2(3 BYTE), 
    "FAILOVER_TYPE" VARCHAR2(13 BYTE), 
    "FAILOVER_METHOD" VARCHAR2(10 BYTE), 
    "FAILED_OVER" VARCHAR2(3 BYTE), 
    "RESOURCE_CONSUMER_GROUP" VARCHAR2(32 BYTE), 
    "PDML_STATUS" VARCHAR2(8 BYTE), 
    "PDDL_STATUS" VARCHAR2(8 BYTE), 
    "PQ_STATUS" VARCHAR2(8 BYTE), 
    "CURRENT_QUEUE_DURATION" NUMBER, 
    "CLIENT_IDENTIFIER" VARCHAR2(64 BYTE), 
    "BLOCKING_SESSION_STATUS" VARCHAR2(11 BYTE), 
    "BLOCKING_INSTANCE" NUMBER, 
    "BLOCKING_SESSION" NUMBER, 
    "FINAL_BLOCKING_SESSION_STATUS" VARCHAR2(11 BYTE), 
    "FINAL_BLOCKING_INSTANCE" NUMBER, 
    "FINAL_BLOCKING_SESSION" NUMBER, 
    "SEQ#" NUMBER, 
    "EVENT#" NUMBER, 
    "EVENT" VARCHAR2(64 BYTE), 
    "P1TEXT" VARCHAR2(64 BYTE), 
    "P1" NUMBER, 
    "P1RAW" RAW(8), 
    "P2TEXT" VARCHAR2(64 BYTE), 
    "P2" NUMBER, 
    "P2RAW" RAW(8), 
    "P3TEXT" VARCHAR2(64 BYTE), 
    "P3" NUMBER, 
    "P3RAW" RAW(8), 
    "WAIT_CLASS_ID" NUMBER, 
    "WAIT_CLASS#" NUMBER, 
    "WAIT_CLASS" VARCHAR2(64 BYTE), 
    "WAIT_TIME" NUMBER, 
    "SECONDS_IN_WAIT" NUMBER, 
    "STATE" VARCHAR2(19 BYTE), 
    "WAIT_TIME_MICRO" NUMBER, 
    "TIME_REMAINING_MICRO" NUMBER, 
    "TIME_SINCE_LAST_WAIT_MICRO" NUMBER, 
    "SERVICE_NAME" VARCHAR2(64 BYTE), 
    "SQL_TRACE" VARCHAR2(8 BYTE), 
    "SQL_TRACE_WAITS" VARCHAR2(5 BYTE), 
    "SQL_TRACE_BINDS" VARCHAR2(5 BYTE), 
    "SQL_TRACE_PLAN_STATS" VARCHAR2(10 BYTE), 
    "SESSION_EDITION_ID" NUMBER, 
    "CREATOR_ADDR" RAW(8), 
    "CREATOR_SERIAL#" NUMBER, 
    "ECID" VARCHAR2(64 BYTE), 
    "TS" TIMESTAMP (6), 
    "SNAP" NUMBER, 
    "INFO" VARCHAR2(100 BYTE)
   ) 
  TABLESPACE "BLOCKMON" ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu dem Problem kommen, dass einige Spalten fehlen. Daher muss hier in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table sessionlog;
create table sessionlog as (select s.*,sysTIMESTAMP ts,1 snap,cast('x' as  VARCHAR2(100)) info  from gv$session s where 1=0);

3-4- DDL für die Tabelle SQLLOG

  CREATE TABLE "BLOCKMON"."SQLLOG" 
   (    "INST_ID" NUMBER, 
    "SQL_TEXT" VARCHAR2(1000 BYTE), 
    "SQL_FULLTEXT" CLOB, 
    "SQL_ID" VARCHAR2(13 BYTE), 
    "SHARABLE_MEM" NUMBER, 
    "PERSISTENT_MEM" NUMBER, 
    "RUNTIME_MEM" NUMBER, 
    "SORTS" NUMBER, 
    "LOADED_VERSIONS" NUMBER, 
    "OPEN_VERSIONS" NUMBER, 
    "USERS_OPENING" NUMBER, 
    "FETCHES" NUMBER, 
    "EXECUTIONS" NUMBER, 
    "PX_SERVERS_EXECUTIONS" NUMBER, 
    "END_OF_FETCH_COUNT" NUMBER, 
    "USERS_EXECUTING" NUMBER, 
    "LOADS" NUMBER, 
    "FIRST_LOAD_TIME" VARCHAR2(19 BYTE), 
    "INVALIDATIONS" NUMBER, 
    "PARSE_CALLS" NUMBER, 
    "DISK_READS" NUMBER, 
    "DIRECT_WRITES" NUMBER, 
    "BUFFER_GETS" NUMBER, 
    "APPLICATION_WAIT_TIME" NUMBER, 
    "CONCURRENCY_WAIT_TIME" NUMBER, 
    "CLUSTER_WAIT_TIME" NUMBER, 
    "USER_IO_WAIT_TIME" NUMBER, 
    "PLSQL_EXEC_TIME" NUMBER, 
    "JAVA_EXEC_TIME" NUMBER, 
    "ROWS_PROCESSED" NUMBER, 
    "COMMAND_TYPE" NUMBER, 
    "OPTIMIZER_MODE" VARCHAR2(10 BYTE), 
    "OPTIMIZER_COST" NUMBER, 
    "OPTIMIZER_ENV" RAW(2000), 
    "OPTIMIZER_ENV_HASH_VALUE" NUMBER, 
    "PARSING_USER_ID" NUMBER, 
    "PARSING_SCHEMA_ID" NUMBER, 
    "PARSING_SCHEMA_NAME" VARCHAR2(30 BYTE), 
    "KEPT_VERSIONS" NUMBER, 
    "ADDRESS" RAW(8), 
    "TYPE_CHK_HEAP" RAW(8), 
    "HASH_VALUE" NUMBER, 
    "OLD_HASH_VALUE" NUMBER, 
    "PLAN_HASH_VALUE" NUMBER, 
    "CHILD_NUMBER" NUMBER, 
    "SERVICE" VARCHAR2(64 BYTE), 
    "SERVICE_HASH" NUMBER, 
    "MODULE" VARCHAR2(64 BYTE), 
    "MODULE_HASH" NUMBER, 
    "ACTION" VARCHAR2(64 BYTE), 
    "ACTION_HASH" NUMBER, 
    "SERIALIZABLE_ABORTS" NUMBER, 
    "OUTLINE_CATEGORY" VARCHAR2(64 BYTE), 
    "CPU_TIME" NUMBER, 
    "ELAPSED_TIME" NUMBER, 
    "OUTLINE_SID" NUMBER, 
    "CHILD_ADDRESS" RAW(8), 
    "SQLTYPE" NUMBER, 
    "REMOTE" VARCHAR2(1 BYTE), 
    "OBJECT_STATUS" VARCHAR2(19 BYTE), 
    "LITERAL_HASH_VALUE" NUMBER, 
    "LAST_LOAD_TIME" VARCHAR2(19 BYTE), 
    "IS_OBSOLETE" VARCHAR2(1 BYTE), 
    "IS_BIND_SENSITIVE" VARCHAR2(1 BYTE), 
    "IS_BIND_AWARE" VARCHAR2(1 BYTE), 
    "IS_SHAREABLE" VARCHAR2(1 BYTE), 
    "CHILD_LATCH" NUMBER, 
    "SQL_PROFILE" VARCHAR2(64 BYTE), 
    "SQL_PATCH" VARCHAR2(30 BYTE), 
    "SQL_PLAN_BASELINE" VARCHAR2(30 BYTE), 
    "PROGRAM_ID" NUMBER, 
    "PROGRAM_LINE#" NUMBER, 
    "EXACT_MATCHING_SIGNATURE" NUMBER, 
    "FORCE_MATCHING_SIGNATURE" NUMBER, 
    "LAST_ACTIVE_TIME" DATE, 
    "BIND_DATA" RAW(2000), 
    "TYPECHECK_MEM" NUMBER, 
    "IO_CELL_OFFLOAD_ELIGIBLE_BYTES" NUMBER, 
    "IO_INTERCONNECT_BYTES" NUMBER, 
    "PHYSICAL_READ_REQUESTS" NUMBER, 
    "PHYSICAL_READ_BYTES" NUMBER, 
    "PHYSICAL_WRITE_REQUESTS" NUMBER, 
    "PHYSICAL_WRITE_BYTES" NUMBER, 
    "OPTIMIZED_PHY_READ_REQUESTS" NUMBER, 
    "LOCKED_TOTAL" NUMBER, 
    "PINNED_TOTAL" NUMBER, 
    "IO_CELL_UNCOMPRESSED_BYTES" NUMBER, 
    "IO_CELL_OFFLOAD_RETURNED_BYTES" NUMBER, 
    "SNAP" NUMBER, 
    "TS" TIMESTAMP (6)
   ) 
  TABLESPACE "BLOCKMON" 
 LOB ("SQL_FULLTEXT") STORE AS BASICFILE (
  TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION 
  NOCACHE LOGGING 
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)) ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu dem Problem kommen, dass einige Spalten fehlen. Daher muss hier in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table sqllog;
create table sqllog as (select s.*,1 snap,sysTIMESTAMP ts from gv$sql s where 1=0);

3-5- DDL für die Tabelle SQLTEXTLOG

  CREATE TABLE "BLOCKMON"."SQLTEXTLOG" 
   (    "INST_ID" NUMBER, 
    "ADDRESS" RAW(8), 
    "HASH_VALUE" NUMBER, 
    "SQL_ID" VARCHAR2(13 BYTE), 
    "COMMAND_TYPE" NUMBER, 
    "PIECE" NUMBER, 
    "SQL_TEXT" VARCHAR2(64 BYTE), 
    "SNAP" NUMBER
   ) 
  TABLESPACE "BLOCKMON" ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu dem Problem kommen, dass einige Spalten fehlen. Daher muss hier in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table sqltextlog;
create table sqltextlog as (select s.*,1 snap from gv$sqltext s where 1=0);

3-6- DDL für die Tabelle TEST

  CREATE TABLE "BLOCKMON"."TEST" 
   (    "N" NUMBER
   ) 
  TABLESPACE "BLOCKMON" ;

4) Mehrere VIEWS als User BLOCKMON erstellen

4-1- DDL for View V_BLOCKED_SESSIONS

CREATE OR REPLACE FORCE VIEW "BLOCKMON"."V_BLOCKED_SESSIONS" ("TIMESTAMP", "SNAP", "INFO", "INST_ID", "SID", "USERNAME", "WAIT_CLASS",

"EVENT", "SECONDS_IN_WAIT", "SQL_ID", "SQL_TEXT") AS 
  select se.ts timestamp,se.snap,se.info,se.inst_id,se.sid,se.username,se.wait_class,se.event,se.seconds_in_wait,sq.sql_id,sq.sql_text
from sessionlog se,sqllog sq
where info='blocked'
and se.snap=sq.snap(+)
and se.sql_id=sq.sql_id(+);

4-2- DDL for View V_BLOCKING_DATA

CREATE OR REPLACE FORCE VIEW "BLOCKMON"."V_BLOCKING_DATA" ("SNAP", "INST_ID", "SID", "SQL_ID", "INFO", "WAIT_CLASS", "EVENT",

"SECONDS_IN_WAIT", "TIMESTAMP") AS 
  select se.snap,se.inst_id,se.sid,se.sql_id,se.info,se.wait_class,se.event,se.seconds_in_wait,se.ts timestamp from sessionlog se, killlog

ki,sqllog sq
where se.snap=ki.snap
and se.snap=sq.snap(+)
and se.inst_id=ki.inst_id
and se.sid=ki.sid
and se.sql_id=sq.sql_id(+);

4-3- DDL for View V_KILLED_SESSIONS

  CREATE OR REPLACE FORCE VIEW "BLOCKMON"."V_KILLED_SESSIONS" ("TIMESTAMP", "SNAP", "INFO", "INST_ID", "SID", "USERNAME", "WAIT_CLASS",

"EVENT", "SECONDS_IN_WAIT", "SQL_ID", "SQL_TEXT") AS 
  select ki.ts timestamp,ki.snap,se.info,ki.inst_id,ki.sid,se.username,se.wait_class,se.event,se.seconds_in_wait,sq.sql_id,sq.sql_text
from killlog ki,sessionlog se,sqllog sq
where ki.snap=se.snap
and ki.inst_id=se.inst_id
and ki.sid=se.sid
and se.info='blocker'
and se.snap=sq.snap(+)
and se.sql_id=sq.sql_id(+);

5) SEQUENCES als User BLOCKMON erstellen

DDL for Sequence SEQ

CREATE SEQUENCE  "BLOCKMON"."SEQ"  MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 607041 CACHE 20 NOORDER NOCYCLE ;

6) PROZEDUR WATCHDOG als User BLOCKMON erstellen

DDL for Procedure WATCHDOG

set define off;  
 
create or replace procedure BLOCKMON.watchdog as
snapid number;
rsid number;
sqlid varchar2(100);
stm varchar2(4000);
msg varchar2(32000);
blkdmsg varchar2(32000);
blkdsql varchar2(32000);
crlf varchar2(100):=chr(13)||chr(10);
flag number;
begin
select seq.nextval into snapid from dual;
for s in (select * from gv$session where blocking_session is not null) loop
--session
  insert into sessionlog (select s1.*,systimestamp,snapid,'blocked' from gv$session s1 where inst_id=s.inst_id and sid=s.sid);


 insert into sessionlog  (select s1.*,systimestamp,snapid,'blocker' from gv$session s1 where inst_id=s.blocking_instance and sid=s.blocking_session);


 insert into sessionlog  (select s1.*,systimestamp,snapid,'finalblocker' from gv$session s1 where inst_id=s.final_blocking_instance and sid=s.final_blocking_session);


--sql
  insert into sqllog (select s1.*,snapid,systimestamp from gv$sql s1 where sql_id=(select sql_id from gv$session s1 where inst_id=s.inst_id and sid=s.sid));


  insert into sqllog (select s1.*,snapid,systimestamp from gv$sql s1 where sql_id=(select sql_id from gv$session s1 where inst_id=s.blocking_instance and sid=s.blocking_session));


  insert into sqllog (select s1.*,snapid,systimestamp from gv$sql s1 where sql_id=(select sql_id from gv$session s1 whereinst_id=s.final_blocking_instance and sid=s.final_blocking_session));


--lock  
insert into locklog (select s1.*,snapid,systimestamp from gv$lock s1 where inst_id=s.inst_id and sid=s.sid);
insert into locklog (select s1.*,snapid,systimestamp from gv$lock s1 where inst_id=s.blocking_instance and sid=s.blocking_session);
insert into locklog (select s1.*,snapid,systimestamp from gv$lock s1 where inst_id=s.final_blocking_instance and sid=s.final_blocking_session);
--sqltext
insert into sqltextlog (select s1.*,snapid from gv$sqltext s1 where inst_id=s.inst_id and sql_id=s.sql_id);

blkdmsg:='instance:'||s.inst_id||crlf;
blkdmsg:=blkdmsg||'sid:'||s.sid||crlf;
blkdmsg:=blkdmsg||'username:'||s.username||crlf;
blkdmsg:=blkdmsg||'program:'||s.program||crlf;
blkdmsg:=blkdmsg||'module:'||s.module||crlf;
blkdmsg:=blkdmsg||'wait_class:'||s.wait_class||crlf;
blkdmsg:=blkdmsg||'evnt:'||s.event||crlf;
blkdmsg:=blkdmsg||'seconds_in_wait:'||s.seconds_in_wait||crlf;
blkdmsg:=blkdmsg||crlf;
  
flag:=0;
blkdsql:='';
for r in (select distinct piece,sql_text from sqltextlog where sql_id=s.sql_id order by piece) loop
  blkdsql:=blkdsql||r.sql_text||crlf;
  flag:=1;
end loop;
if flag=0 then 
  blkdsql:='--NONE--'||crlf;  
end if;
  
--kill nur final blocker
  if s.seconds_in_wait>=30 then
    for b in (select * from gv$session where inst_id=s.final_blocking_instance and sid=s.final_blocking_session) loop
--sqltext
    insert into sqltextlog (select s1.*,snapid from gv$sqltext s1 where inst_id=b.inst_id and sql_id=b.sql_id);
      
      
      stm:='alter system kill session '''||b.sid||','||b.serial#||',@'||b.inst_id||'''';
      insert into killlog values (snapid,systimestamp,b.inst_id,b.sid,stm);
msg:='will try to kill('||stm||')'||chr(10)||chr(13)||'(if this mail is not sent again, the kill has been successful)'||crlf;    
msg:=msg||crlf;
msg:=msg||'(there will be one mail per blocked session, if there is a cascading block situation, the blocks will be handled sequencially)'||

crlf;    
msg:=msg||crlf;
msg:=msg||'DETAILED INFORMATION:'||crlf;
msg:=msg||'---------------------'||crlf;
msg:=msg||crlf;
msg:=msg||'BLOCKER SESSION:'||crlf;
msg:=msg||'----------------'||crlf;
msg:=msg||'instance:'||b.inst_id||crlf;
msg:=msg||'sid:'||b.sid||crlf;
msg:=msg||'username:'||b.username||crlf;
msg:=msg||'program:'||b.program||crlf;
msg:=msg||'module:'||b.module||crlf;
msg:=msg||'wait_class:'||b.wait_class||crlf;
msg:=msg||'event:'||b.event||crlf;
msg:=msg||'seconds_in_wait:'||b.seconds_in_wait||crlf;
msg:=msg||crlf;
msg:=msg||'BLOCKED SESSION:'||crlf;
msg:=msg||'-------------------'||crlf;
msg:=msg||blkdmsg;
msg:=msg||crlf;
msg:=msg||'Current Statements:'||crlf;
msg:=msg||'-------------------'||crlf;
msg:=msg||'BLOCKER(normaly NONE):'||crlf;
flag:=0;
for r in (select distinct piece,sql_text from sqltextlog where sql_id=b.sql_id order by piece) loop
  msg:=msg||r.sql_text||crlf;
  flag:=1;
end loop;
if flag=0 then 
  msg:=msg||'--NONE--'||crlf;
end if;
msg:=msg||crlf;
msg:=msg||'BLOCKED:'||crlf;
msg:=msg||blkdsql||crlf;
msg:=msg||crlf;
msg:=msg||'historical data in schema BLOCKMON:'||crlf;
msg:=msg||'select * from blockmon.v_blocked_sessions where snap=<snap>'||crlf;
msg:=msg||'select * from blockmon.v_killed_sessions where snap=<snap>'||crlf;
msg:=msg||'Base Tables:'||crlf;
msg:=msg||'KILLLOG'||crlf;
msg:=msg||'LOCKLOG'||crlf;
msg:=msg||'SESSIONLOG'||crlf;
msg:=msg||'SQLLOG'||crlf;
msg:=msg||'SQLTEXTLOG'||crlf;

msg:=msg||crlf;

          utl_mail.send(
    sender      =>    'NAME@xyxyxy.com',
    recipients  =>  'EMPFÄNGER@xyxyxy.com, EMPFÄNGER@xyxyxy.com ',  
    cc          =>    'EMPFÄNGER@xyxyxy.com ',
    bcc         =>    '',
    subject     =>    'BLOCKER DETECTED (snap '||snapid||')',
    message     =>    msg,
    mime_type   =>    'text/plain; charset=us-ascii',
    priority    =>    NULL);
      begin
--      null;
      execute immediate stm;                                    
      exception when others then null;
      end;
      dbms_output.put_Line(stm);
    end loop;
  end if;
end loop;
end;
/

Falls man vorher testen möchte ob die Blocking Sessions richtig gekillt werden, muss man den Eintrag „execute immediate stm;“ auskommentieren.

Dadurch werden die Blocker nicht gekillt, sondern nur E-Mails verschickt mit der Info welche Session gekillt werden sollten.

begin
    null;
--      execute immediate stm;                                    
      exception when others then null;
      end;
     dbms_output.put_Line(stm);

Wie schon oben bei den einzelnen Tabellen beschrieben, kann es bei einigen Datenbank-Releases beim Insert in den folgenden Tabellen zum Problem kommen, dass einige Spalten fehlen, die aber auf den entsprechenden Datenbank-Releases in den jeweiligen gv$ Views vorhanden sind:

sqllog, sessionlog, locklog, sqltextlog

Daher muss hier in solchen Fällen die Struktur von den jeweiligen gv$ Views übernommen- und in den Tabellen die fehlenden Spalten ergänzt werden.

Als BLOCKMON:

drop table locklog;
create table locklog as (select s.*,1 snap,sysTIMESTAMP ts from gv$lock s where 1=0);

drop table sqllog;
create table sqllog as (select s.*,1 snap,sysTIMESTAMP ts from gv$sql s where 1=0);

drop table sessionlog;
create table sessionlog as (select s.*,sysTIMESTAMP ts,1 snap,cast('x' as  VARCHAR2(100)) info  from gv$session s where 1=0);

drop table sqltextlog;
create table sqltextlog as (select s.*,1 snap from gv$sqltext s where 1=0);

7) ACL EINRICHTEN

BEGIN
  DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('netacl.xml',
      'Allow usage to the UTL network packages', 'BLOCKMON', TRUE,
'connect');

  DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE('netacl.xml' ,'BLOCKMON', TRUE,
'resolve');

  DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('netacl.xml','*');
END;
/

8) Falls kein UTL_MAIL installiert -> UTL_MAIL installieren

select * from dba_objects where object_name='UTL_MAIL';        => kein UTL_MAIL installiert

installieren des UTL_MAILS:
@utlmail.sql
@prvtmail.plb


 Rechte fehlen (BLOCKMON):
 grant execute on utl_mail to BLOCKMON;

9) SMTP EINRICHTEN

SQL> alter system set smtp_out_server='mail.xyxyxy.com';
System altered.

SQL> show parameter smtp

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
smtp_out_server                      string      mail.xyxyxy.com

10)  TESTEN

Zum Testen kann eine Blocking-Session erstellt werden und getestet werden, ob der Kill-Blocker richtig eingerichtet wurde.

1- Blockingsessions erzeugen:

BLOCKMON User:
insert into TEST values(1);
commit;
update TEST set n=2;

Nun nochmal mit einem anderen User.

update BLOCKMON.TEST set n=3;

=> Blockingsessions erzeugt!!!
3- Prozedur ausführen als BLOCKMON USER (am besten ohne kill):

=> nach 30 Sekunden:
begin
watchdog;
end;
/

Falls der Test erfolgreich verläuft, kann das Killen wieder aktiviert- und der Job dafür eingerichtet werden.

11) JOB FÜR BLOCKMON USER EINRICHTEN

Nun muss noch folgender Job zum Ausführen des WATCHDOGs eingerichtet werden:

begin
dbms_scheduler.create_job(
job_name=>'BLOCKMON.WATCHDOG_JOB',
job_type=>'PLSQL_BLOCK',
job_action=>'begin watchdog;end;',
repeat_interval=>'freq=minutely',
enabled=>true);
end;
/

12) Abschließend

Durch das Einrichten des WATCHDOG_JOB wird die Oracle Datenbank laufend aktiv auf blockierende Sessions überprüft und ein aufgespührter Blocker automatisch beendet.

In der WATCHDOG Procedure (Punkt 6)  werden alle Einstellungen vorgenommen, um die Kill-Voraussetzungen für Blocking Sessions anzupassen.

Oracle Scheduler Jobs Kurzfassung

Oracle Scheduler Jobs – eine Kurzfassung

Wer regelmäßig automatische Vorgänge in seiner Datenbank laufen lässt, wie zum Beispiel das Aufrufen von Services, Datenübernahmen oder regelmäßige Berechnungen, der wird sehr bald auf Oracle Scheduler Jobs treffen. Diese können auf verschiedene Arten regelmäßig Prozeduren und ähnliches in regelmäßigen Abständen ausführen.

Die grundlegende Definition benötigt zumindest folgende Parameter:

  • job_name: der Name des Scheduler Jobs
  • job_type: der Typ des Scheduler Jobs, ist es ein PL/SQL Block oder ein direkter Prozeduraufruf, …
  • job_action: der tatsächlich auszuführende Ausdruck (abhängig von job_type)

und würde dann so aussehen:

Weiterlesen

Oracle streicht 450 Support Stellen

Oracle streicht in Europa 450 Stellen im Support

Wie zahlreiche Medien berichten, baut Oracle in Europa 450 Stellen im Support ab, alleine 150 davon in Deutschland. Ziel der Maßnahme ist die Verlegung des Supports nach Rumänien.

Alle europäischen Oracle Support Standorte sollen bis Ende März 2016 geschlossen werden – das betrifft sämtliche Support-Zentren mit den Ausnahmen von England, Holland und Rumänien.

Zukünftig werden die Support Anfragen aus Deutschland, Österreich und der Schweiz von rumänischen Oracle Support Mitarbeiter/innen beantwortet.

Wie sehr diese Entwicklung Auswirkungen auf die Qualität der deutschsprachigen Unterstützung und auf die dahinter stehenen Prozesse haben wird, kann nur die Praxis zeigen.

DBConcepts – wir sprechen Ihre Sprache

Bei wichtigen und dringenden Support Aufgaben ist es oft von Vorteil, wenn alle Gesprächspartner die gleiche Sprache sprechen und sich auch in der selben Zeitzone befinden.

Alle unsere Remote DBA Mitarbeiter/innen sprechen selbstverständlich Deutsch, um Sie ohne Verständigungsprobleme optimal bei Ihren Anforderungen unterstützen zu können.

Wir befinden uns in Ihrer Zeitzone und sind nur einen Anruf entfernt.

Link: Weiter Infos zu Datenbank Fernwartung durch Remote DBA >>

 

Medien Quellen:

http://www.it-zoom.de/dv-dialog/e/oracle-support-rumaenien-12621/

http://www.heise.de/ix/meldung/Deutscher-Oracle-Kundendienst-schliesst-Ende-Maerz-3117680.html

DOAG Artikel

 

Oracle 12c In-Memory Option Patchset 12.1.0.2

Oracle 12c mit In-Memory Option im Patchset 12.1.0.2 veröffentlicht

Am 22. Juli 2014 veröffentlichte Oracle Inc. das erste Patchset (12.1.0.2.0) für die 12c Datenbank.

Das Patchset enthält viele interessante neue Features, die es Wert sind, genauer unter die Lupe genommen zu werden.

  • Die bereits im Vorjahr auf der OpenWorld angekündigte In-Memory Option ist nun verfügbar.
    Die In-Memory Option enthält folgende Funktionalitäten:

    • In-Memory Column Store (Link)
    • Fault Tolerant In-Memory Column Store (setzt Exadata oder Supercluster voraus)
    • In-Memory Aggregation (Link)
    • ACHTUNG: Die In-Memory Option ist eine Option der Enterprise Edition und kann daher zu zusätzlichen Lizenzkosten führen (Link)
  • Force Full Caching Mode
    • Force Caching ist nun für alle Objekte möglich (Link)
    • Überprüfen Sie vorab, ob die Größe Ihre Datenbank in die SGA passt und aktivieren Sie dieses neue Features (ALTER DATABASE FORCE FULL DATABASE CACHING)
  • Automatic Big Table Caching
    • Dieses neue Feature ermöglicht es, große Tabellen in einem separaten Buffer zu speichern. Dadurch können Cache Rotations verhindert werden. (Link)
    • Der Big Table Cache ist ein Prozentteil des BUFFER CACHE. Es macht daher Sinn, die Memory Size zu überprüfen (zum Aktivieren verwenden Sie den DB_BIG_TABLE_CACHE_PERCENT_TARGET Paramteter)
    • Das Feature wird für Parallel Query beim RAC mit PARALLEL_DEGREE_POLICY auf AUTO oder ADAPTIVE unterstützt.
    • Auch auf Single Instanzenen für Single und Prallel Query
  • Advanced Index Compression
    • Ermöglicht Indexes auf effiziente Art zu komprimieren (Link)
    • Achtung: Dieses neue Features ist Teil der Advanced Compression Option kann daher zu zusätzlichen Lizenzkosten führen (Link)
  • READ Privilege
    • In früheren Releases gab es oft Probleme mit Usern, die das SELECT Recht auf spezielle Tables gegranted hatten. Dadurch ware es möglich, dass Tabellen in Exclusive Mode gelocked waren oder eine SELECT … FOR UPDATE möglich war. (Link)  Die neue Berechtigung “READ” wurde eingeführt und diese Problematik in Zukunft zu verhindern. (Link)
  • Viele neue Features für CDB und PDBs:
    • Flashback Data Archive (FDA) Unterstützung für CDBs (Link)
    • PDB CONTAINERS Clause
      • Query tables in einenm Subset von PDBs (Link)
    • PDB File Placement in OMF (Link)
    • PDB Logging Clause
      • Turn on NOLOGGING // LOGGING for the whole PDB (Link)
    • PDB Metadata Clone (Link)
    • PDB Remote Clone
      • Ein PDB // Non-CDB über einen Datenbank Link Clonen? Ja, natürlich ist das möglich (Link)
    • PDB Subset Cloning
      • Die USER_TABLESPACES Clause spezifiziert welcher Tablespace in der Plugable Database (PDB) verfügbar sein soll (Link)
    • PDB STANDBYS Clause (Link)
    • PDB State Management Across CDB restart. Dieses Features hat in der 12.1.0.1 wirklich gefehlt. Details hier oder eine Beschreibung des alten Problems finden Sie hier)

Abgesehen von dieser Aufzählung gibt es noch zahlreiche zustätzliche neue Features, die im Feature Guide aufgelistet sind (Link)

 

select blobs über Datenbank Link

Große BLOBs über einen Datenbank Link selektieren

Heute habe ich versucht ein BLOB über einen Datenbank Link zu selektieren.

Ich weiß, es gibt in solchen Fällen einige Einschränkungen, aber in diesem Fall gab mir der Business Case keine andere Wahl.

Mein Ziel war daher die BLOBs über einen Datenbank Link transparent zu selektieren. Einen passenden Workaround konnte ich nicht finden. Von support.oracle.com kam folgendes Statement:

 

  • SELECT with a LOB and DBLink Returns an ORA-22992: Cannot Use LOB Locators Selected from Remote tables (Doc ID 1234893.1)
    • “The error is expected because the use of DBLinks and LOBs via the SELECT from PL/SQL is not supported.”
  • Ora-22992 workaround (Doc ID 436707.1)
    • Getting ORA-1406 with lobs greater than 32KB – 1
  • ORA-1406: Fetched Column Value was Truncated When Selecting Remote Column into Local BLOB Variable (Doc ID 459557.1)
    • “This means that we are not able to retrieve BLOBs columns greater than 32KB – 1 in size through a database link.”

Zusammengefasst bedeutet diese Aussage, dass ein BLOB nativ über einen Datenbank Link nicht selektiert werden kann, falls dieser großer als 32KB-1 ist. Interessante Tatsache in diesem Zusammenhang ist, dass man DBMS_LOB Operators auf der lokalen und remoten Seite verwenden kann.

Mein persönlicher Favorit ist die DBMS_LOB.SUBSTR Funktion. Der Name der Funktion ist etwas ungenau, denn man kann damit BLOBs und auch CLOBs ansprechen.

 

Daraus hat sich mein folgender Ansatz ergeben, um BLOBs über einen Datenbank Link selektieren zu können:

Lösung VERSION 1 (Chunk Methode):

create or replace function GETBLOBVIADBLINK
( dblnk in varchar2
  ,tbl  in varchar2
  ,col  in varchar2
  ,rwid in urowid)
return blob
is
  retval blob;
  tmpraw raw(2000);  
  tmplen number;
  tmpchk number;
  chksize number;
begin
  --preset vars
  chksize:=2000;
  dbms_lob.createtemporary (retval,true);
  execute immediate 'select dbms_lob.getlength@'||dblnk||' ('||col||') from '||tbl||'@'||dblnk||' where rowid=:rwid' into tmplen using rwid;
  
  -- precalc  
  tmpchk:=floor(tmplen/chksize);

  -- applicate frist chunks  
  for i in 0 .. tmpchk-1
  loop  
    execute immediate 'select dbms_lob.substr@'||dblnk||'('||col||','||chksize||','||((i*chksize)+1)||') from '||tbl||'@'||dblnk||' where rowid=:rwid' into tmpraw using rwid;
    dbms_lob.append(retval,tmpraw);
  end loop;
  
  -- applicate last entry
  if (tmplen-(tmpchk*chksize)) > 0 then
    execute immediate 'select dbms_lob.substr@'||dblnk||'('||col||','||(tmplen-(tmpchk*chksize))||','||((tmpchk*chksize)+1)||') from '||tbl||'@'||dblnk||' where rowid=:rwid' into tmpraw using rwid;
    dbms_lob.append(retval,tmpraw);
  end if;
  return retval;
end;
/

Die Erklärung der Funktion ist sehr einfach:

  1. Ein TEMP LOB auf der lokalen Seite erstellen
  2. Die Limitation von DBMS_LOB.SUBSTR als RAW(2000) als mximale chunk size definieren
  3. Die einzelnen Chunks (max 2000 bytes) über den Datenbank Link kopieren und mit den Chunks auf der lokalen Seiten temporär ein BLOB zusammenfügen
  4. Das BLOB lokal auf dem Aufrufer übergeben

In Anschluss daran eine VIEW mit den neuen Definitionen erstellen:

CREATE OR REPLACE FORCE VIEW TESTVW1 (ID, MYLOB) AS 
SELECT id
       ,getblobviadblink('ARCHIV','MYLOBTABLE','MYLOB',rowid) MYLOB
FROM  MYLOB@archiv;

Fertig.
Nun ist es möglich über einen Datenbank Link auch größere BLOBs als 32KB-1 zu selektieren!

 

Es gibt aber auch noch andere Lösungswege:

Lösung VERSION 2 (temporary table Methode)

create global temporary table tmplob (tmplob blob) ON COMMIT PRESERVE ROWS;
create or replace function getblobviadblink2
( dblnk in varchar2
  ,tbl  in varchar2
  ,col  in varchar2
  ,rwid in urowid)
return blob
is
  PRAGMA AUTONOMOUS_TRANSACTION;
  retval blob;
begin

  execute immediate 'insert /*+ NOLOGGING */ into tmplob select '||col||' from '||tbl||'@'||dblnk||' where rowid=:rwid' using rwid;
  select tmplob into retval from tmplob;
  delete /*+ NOLOGGING */ from tmplob;
  commit;
  return retval;
end;
/

Beide Methoden sind möglich, aber die Version 2 ist wesentlich schneller.

Darüber hinaus gibt es sicherlich auch noch andere Lösungsmöglichkeiten.

Ich würde mich freuen, wenn Sie im Kommentar Ihre Erfahrungen posten.

 

 

Oracle Securefiles Performance Boost

Performance Boost mit SecureFiles und NOLOGGING

In diesem Beitrag vergleichen wir SecureFiles und BasicFiles. Es gibt einige Beiträge auf anderen Webseiten die zeigen wie schnell Secure Files sind, aber ich möchte diesmal einige Fakten und Benefits der NOLOGGING Option aufzeigen, welche bereits in einem früheren Beitrag auf diesem Blog beschrieben wurde.

The default value of the initialization parameter DB_SECUREFILE has changed in 12c from PERMITTED to PREFERRED

Die Test Umgebung

Alle hier angeführten Test wurden auf unserer eigenen Oracle Exadata X2 (Patch Level Jänner 2014) unter OEL5 auf einer 11.2.0.4 Datenbank durchgeführt.

Es wurde dafür die Tabelle lob_test erstellt und die NOCACHE Option aktiviert, welche mit der NOLOGGING Option zwingend notwendig ist.

CREATE TABLE lob_test (id     raw(16) default sys_guid() primary key,
                       lob1 BLOB,
                       lob2 BLOB,
                       lob3 BLOB,
                       lob4 BLOB,
                       lob5 BLOB)
        LOB(lob1) STORE AS SECUREFILE(
                  NOCOMPRESS NOCACHE LOGGING )
        LOB(lob2) STORE AS SECUREFILE(
                  NOCOMPRESS NOCACHE NOLOGGING)
        LOB(lob3) STORE AS SECUREFILE(
                  NOCOMPRESS NOCACHE FILESYSTEM_LIKE_LOGGING)
        LOB(lob4) STORE AS BASICFILE  (
                        NOCACHE LOGGING )
        LOB(lob5) STORE AS BASICFILE  (
                        NOCACHE NOLOGGING);

Das wurde getestet

Zuerst wurde ein Load und Unload Test mit 5 Gigabyte Daten (500 Files) durchgeführt, wobei jede einzelne Column seperat getestet wurde. Es wurden Basicfile vs. SecureFile und die NOLOGGING Option vs. LOGGING Option verglichen. Zusätzlich wurde auch die FILESYSTEM_LIKE_LOGGING Option gestestet, welche laut Dokumentation keinen bzw. minimalen Effekt in Vergleich zu NOLOGGING zeigen sollte:

In this case, if NOLOGGING is the default value, the SecureFile will default to FILESYSTEM_LIKE_LOGGING.

Bitte beachten Sie, dass es sich bei den Tests nicht um einen klassischen Performance Benchmark, sondern um die Simmulation einer üblichen Applikation handelt. Die Ergebnisse zeigen einen Vergleich der Performance Steigerungen auf der eingesetzten Hardware.

Test #1 Execution Time

Lob Load Time

Die Load Time zeigt die Zeitspanne für das Laden von 500 Files in die Test Tabelle. Die Diffenenz zwischen Lob2 und Lob3 ist marginal, was auch Sinn macht. Das Basicfile Lob5 mit NOLOGGING benötigt 127 Sekunden um die Daten zu laden, im Vergleich dazu benötigt Lob3 nur 14 Sekunden. In diesem Fall ist das Laden via SecureFile also 9x schneller als via Basicfile.

LOB Unload Time

Der umgekehrte Weg beim Unload der 500 Files von der Tabelle in das Filesystem zeigt ein ähnliches Bild. Das SecureFile benötigt circa 550 Sekunden für den Unload, das Basicfile benötigt 2351 Sekunden und ist circa 4x langsamer.

Test #2 IO Performance

LOB IO

Der I/O Durchsatz wird mit MB/s beim Laden in die Tabelle gemessen. Das Securefile erreicht einen Wert von 358/MB auf lokalen Server Harddisks. Das Basicfile erreicht nur 39 MB/s im NOLOGGING Mode.

 

Test #3 NOLOGGING Performance

Redo Size

Die NOLOGGING Performance bedeutet auch wie die Redo Information geschrieben wird. Das Securefile lob1 benötigt circa 5100MB Redo, was etwa der Datenmenge entspricht die in die Datenbank geladen wurde.

Interessant ist, dass das Basicfile 176MB Redo Data benötigt.
Das SecureFile benötigt nur 30MB, was circa 6x geringer ist.