BDLS und die nervige Laufzeit – Ein Akt in 3 Teilen.

Nach einer Systemkopie müssen in der Regel die logischen Systemnamen umgesetzt werden. Und auch unter Netweaver 7.4 lässt die SAP den Kunden ganz schön im Regen stehen. Nicht einmal Standard Indizes für die Felder mit den logischen Systemnamen werden ausgefliefert. Also muss der Kunde hier wieder selbst Hand anlegen.

Eine schnelle und einfache Möglichkeit die Indizes anzulegen habe ich mir mit folgendem Script geschaffen. Der geneigte Admin kann mit dem Script schnell und direkt auf Datenbank-ebene die notwendigen Indizes nach einem Systemrefresh anlegen. Ganz ohne die zeitraubenden brtools.

Das Script lässt sich einfach anpassen und erweitern. Entfernt man zum Beispiel den manuellen vi-Part kann man es mit einem Wrapper versehen und für einen Massenverarbeitung nutzen. Da es eigenständige Logfiles pro Tabelle und Aufruf anlegt kann dies sogar parallelisiert passieren. Das Script an sich ist recht simpel gehalten und sieht so aus:

 

#!/usr/bin/ksh
#Script zum Anlegen von Indizes
#Patrick Wessel, Juni 2012

#Variablen deklarieren
TABELLE=$1 #Uebergebener Tabellennname
FELDER=$2 #Uebergebene Feldnamen
RC=1 #Returncode Pruefung sqlplus Lauf
SUCHRC=1 #Returncode Pruefung Feldpruefung

#Konstanten deklarieren
DATUM=`date ‚+%d%m%Y_%H%M%S’` #Datum fuer die Logfiles
SCHEMA=$dbs_ora_schema #Schema fuer die Indizes
SQLGETTABINFO=get_$(echo $TABELLE | tr ‚/‘ ‚_‘)_info_${DATUM}.sql #SQL Script zum Ermitteln der Tabellenfelder
SQLGETTABINFOLOG=$SQLGETTABINFO.log #Logfile fuer SQL Script zum Ermitteln der Tabellenfelder
SQLCREATEINDEX=create_$(echo $TABELLE | tr ‚/‘ ‚_‘)_${DATUM}.sql #SQL Script zum Erstellen der Indizes
SQLCREATEINDEXLOG=$SQLCREATEINDEX.log #Logfile fuer SQL Script zum der Indizes
PROZENT=10 #Samplesize fuer die Analyse des DB Objects
ZEILEN=5 #Mindestanzahl an Zeilen in den SQL Script Dateien bevor diese ausgeführt werden.

#Uebergabe Parameter pruefen
[ „$TABELLE“ == „“ ] && echo „\n*** Fehler: Es wurde keine Tabelle angegeben“ && exit 1
[ „$FELDER“ == „“ ] && echo „\n*** Fehler: Es wurden keine Felder fuer den Index angeben“ && exit 1

#Bestehende SQL Scripts und Logfiles umbennen
[ -f $SQLCREATEINDEX ] && mv $SQLCREATEINDEX $SQLCREATEINDEX.bak
[ -f $SQLGETTABINFO ] && mv $SQLGETTABINFO $SQLGETTABINFO.bak
[ -f $SQLCREATEINDEXLOG ] && mv $SQLCREATEINDEXLOG $SQLCREATEINDEXLOG.bak
[ -f $SQLGETTABINFOLOG ] && mv $SQLGETTABINFOLOG $SQLGETTABINFOLOG.bak

#Uebergebene Felder aufbereiten
FELDER=$(echo „\“$(echo $FELDER | sed s/,/\“,\“/g)\““)

#Beschreibung fuer die Tabelle auslesen
echo „\nLade Tabellenbeschreibung fuer Tabelle ${SCHEMA}.\“${TABELLE}\“ :“
echo „set echo off;“ | tee -a $SQLGETTABINFO
echo „set termout off;“ | tee -a $SQLGETTABINFO
echo „spool $SQLGETTABINFOLOG“ | tee -a $SQLGETTABINFO
echo „whenever sqlerror exit sql.sqlcode“ | tee -a $SQLGETTABINFO
echo „connect / as sysdba;“ | tee -a $SQLGETTABINFO
echo „desc ${SCHEMA}.\“${TABELLE}\“;“ | tee -a $SQLGETTABINFO
echo „exit;“ | tee -a $SQLGETTABINFO

#Attribute der Erstellten SQL Script Datei ausgeben
ls -al $SQLGETTABINFO

#SQL Script rudimentaer auf Inhalt pruefen und ausfuehren
[ „$(cat ${SQLGETTABINFO} | wc -l)“ -lt $ZEILEN ] && echo „\n**** Die Ausfuehrung wird nicht vorgenommen.\nDas SQL Script hat weniger als $ZEILEN Zeilen.\nAbbruch.“ && exit 0
sqlplus /NOLOG @${SQLGETTABINFO}
RC=$?
[ „$RC“ -eq 0 ] && echo „\nDie Tabellenbeschreibungi fuer ${SCHEMA}.\“${TABELLE}\“ wurde erfolgreich geladen“
[ „$RC“ -ne 0 ] && echo „*** Fehler: sqlplus wurde mit Fehlern beendet.\nDie Tabellenbeschreibung konnte nicht geladen werden\nBitte pruefen!\niGGf. existiert die Tabelle ${SCHEMA}.\“${TABELLE}\“ nicht.\n$(cat $SQLGETTABINFOLOG)“ && exit 1

#Uebergebene Felder pruefen ob diese auch in der Tabelle existieren.
echo „\nPruefe die angegebenen Felder auf Existenz:“
for i in $(echo „${FELDER}“ | sed s/‘,’/‘ ‚/g | sed s/'“‚//g )
do
grep $i $SQLGETTABINFOLOG >/dev/null
SUCHRC=$?
[ „$SUCHRC“ -ne 0 ] && echo „\n**** Das Feld $i konnte in der Tabelle ${SCHEMA}.\“${TABELLE}\“ nicht gefundden werden! ****\nDer Index kann nicht erstellt werden. Das Script wird abgebrochen!“ && exit 1
[ „$SUCHRC“ -eq 0 ] && echo „Feld: $i gefunden“
done

#Script fuer die Index Erstellung zusammen setzen
echo „\nErstelle Indizies fuer Tabelle ${SCHEMA}.\“${TABELLE}\“ :“
#Informationen zu der Tabelle und den Feldern als Kommentar in das Script schreiben um die Informationen fuer eine Scriptmodifikation direkt im Editor zu sehen.
echo „– Die Tabelle mit den Vorhandenen Feldern:“ | tee -a $SQLCREATEINDEX
grep -v „Connected.“ $SQLGETTABINFOLOG | sed ’s/^/– /‘ | tee -a $SQLCREATEINDEX
echo „set echo off;“ | tee -a $SQLCREATEINDEX
echo „set termout off;“ | tee -a $SQLCREATEINDEX
echo „spool $SQLCREATEINDEXLOG“ | tee -a $SQLCREATEINDEX
echo „whenever sqlerror exit sql.sqlcode“ | tee -a $SQLCREATEINDEX
echo „connect / as sysdba;“ | tee -a $SQLCREATEINDEX
echo „CREATE Index ${SCHEMA}.\“${TABELLE}~BDLS\“ on ${SCHEMA}.\“${TABELLE}\“ (${FELDER}) NOLOGGING TABLESPACE P${SCHEMA} PARALLEL;“ | tee -a $SQLCREATEINDEX
echo „ALTER INDEX ${SCHEMA}.\“${TABELLE}~BDLS\“ NOPARALLEL;“ | tee -a $SQLCREATEINDEX
echo „ANALYZE INDEX ${SCHEMA}.\“${TABELLE}~BDLS\“ ESTIMATE STATISTICS SAMPLE ${PROZENT} PERCENT;“ | tee -a $SQLCREATEINDEX
echo „exit;“ | tee -a $SQLCREATEINDEX

#Attribute der Erstellten SQL Script Datei ausgeben
ls -al $SQLCREATEINDEX

#Anpassung des erstellten SQL Scriptes ermöglichen
echo „\n… Datei kann jetzt editiert werden.\nDer Inhalt wird im Anschluss ausgefuehrt\nWenn nicht gewuenscht Dateiinhalt komplett loeschen!“
sleep 3
vi $SQLCREATEINDEX

#Pruefen ob der Inhalt des SQL Scripts geloescht worden ist (dann nicht ausfuehren) ansonsten ausfuehren und Returncode abfragen
[ „$(cat ${SQLCREATEINDEX} | wc -l)“ -lt $ZEILEN ] && echo „\n**** Die Ausfuehrung wird nicht vorgenommen.\nDas SQL Script hat weniger als $ZEILEN Zeilen.\nAbbruch.“ && exit 0
sqlplus /NOLOG @${SQLCREATEINDEX}
RC=$?
[ „$RC“ -eq 0 ] && echo „\nOK: sqlplus wurde erfolgreich ausgefuehrt:\n$(cat $SQLCREATEINDEXLOG)“
[ „$RC“ -ne 0 ] && echo „\n*** Fehler: sqlplus wurde mit Fehlern beendet.\nBitte pruefen!\n$(cat $SQLCREATEINDEXLOG)“ && exit 1

#Das Script wird sauber beendet. Bei Fehlern setzen vorherige Exits entsprechende Returncodes
exit 0


Benutzt wird das Script auf der Shell wie folgt

<Scriptname> <Tabelle> <Feld1,Feld2,Feld3>

./ind_cr.sh /MRSS/D_BAS_ASG MANDT,CHANGED_LOGSYS

Hier wird ein Index für die Tabelle „/MRSS/D_BAS_ASG“ angelegt mit folgenden Feldern: MANDT und CHANGED_LOGSYS. Das Script sollte als ora user ausgeführt werden. Sofern gewünscht kann das Schema angepasst werden, ansonsten wird das Schema aus der Umgebungsvariable gesourced.

Bei einem Fehler (im SQL) bricht das Script ab und gibt das Spoolfile aus. Auf korrekte Tabellen und Feldnamen muss selbst geachtet werden. Es kann immer nur eine Tabelle mit >n< Feldern angegeben werden. Die Felder müssen direkt durch „,“ (Komma) getrennt werden.

Im Filesystem werden folgende Dateien erzeugt:

create__MRSS_D_BAS_ASG_01062015_113416.sql
create__MRSS_D_BAS_ASG.sql_01062015_113416.log

 

create__MRSS_D_BAS_ASG.sql enthält die SQL Anweisungen:
set echo off;
set termout off;
spool create__MRSS_D_BAS_ASG_01062015_113416.sql.log
whenever sqlerror exit sql.sqlcode
connect / as sysdba;
CREATE Index SAPERP."/MRSS/D_BAS_ASG~BDLS" on SAPERP."/MRSS/D_BAS_ASG" (MANDT,CHANGED_LOGSYS) NOLOGGING TABLESPACE PSAPERP PARALLEL;
ALTER INDEX SAPERP."/MRSS/D_BAS_ASG~BDLS" NOPARALLEL;
ANALYZE INDEX SAPERP."/MRSS/D_BAS_ASG~BDLS" ESTIMATE STATISTICS SAMPLE 10 PERCENT;
exit;

create__MRSS_D_BAS_ASG_01062015_113416.sql.log enthält die Ausgabe des sqlplus bzw. die Fehler.

Connected.
CREATE Index SAPERP."/MRSS/D_BAS_ASG~BDLS" on SAPERP."/MRSS/D_BAS_ASG" (MANDT,CHANGED_LOGSYS) NOLOGGING TABLESPACE PSAPERP PARALLEL
                    *
ERROR at line 1:
ORA-00955: name is already used by an existing object 

 

Sollte während der Ausführung bemerkt werden, dass das Script den Inhalt nicht ausführen soll, kann im vi einfach der Inhalt gelöscht werden. Sollte die Datei weniger als 5 Zeilen lang sein wird sie nicht ausgeführt. Man kann die Vorgabe ändern und seine eigene Version des sql Scriptes abspeichern. Diese wird entsprechend am Ende ausgeführt.

Das Script steht hier zum Download bereit. Nach dem Herunterladen ändert man am besten die Endung in „.sh“ und macht es mittels chmod +x ausführbar.

Wenn man sehen möchte für welche Tabellen man bereits Indizes angelegt hat kann man entweder durch die Protokolle schauen oder man fragt aufgrund der gesonderten Indexbenennung einfach im Oracle an. Das sieht dann zum Beispiel so aus:

 

set pages 200 lines 200
select INDEX_NAME,INDEX_TYPE, TABLE_NAME from dba_indexes where INDEX_NAME like '%~BDLS%';

Eine mögliche Ausgabe wäre dann diese hier:

SQL> set pages 200 lines 200
SQL> select INDEX_NAME,INDEX_TYPE, TABLE_NAME from dba_indexes where INDEX_NAME like '%~BDLS%';

INDEX_NAME                     INDEX_TYPE                  TABLE_NAME
------------------------------ --------------------------- ------------------------------
BKPF~BDLS                      NORMAL                      BKPF
RBKP~BDLS                      NORMAL                      RBKP
/COCKPIT/TMSG~BDLS             NORMAL                      /COCKPIT/TMSG
ANEK~BDLS                      NORMAL                      ANEK
MKPF~BDLS                      NORMAL                      MKPF
COBK~BDLS                      NORMAL                      COBK
GLPCA~BDLS                     NORMAL                      GLPCA
CE11001~BDLS                   NORMAL                      CE11001
/MRSS/D_BAS_ASG~BDLS           NORMAL                      /MRSS/D_BAS_ASG
QMEL~BDLS                      NORMAL                      QMEL
STXH~BDLS                      NORMAL                      STXH
SRRELROLES~BDLS                NORMAL                      SRRELROLES
COEP~BDLS                      NORMAL                      COEP
COES~BDLS                      NORMAL                      COES
COFIS~BDLS                     NORMAL                      COFIS
GLFUNCA~BDLS                   NORMAL                      GLFUNCA
GLPCP~BDLS                     NORMAL                      GLPCP
GLPCT~BDLS                     NORMAL                      GLPCT

18 rows selected.

SQL> 

Werden die Indizes nicht mehr benötigt kann man diese einfach wieder droppen:

DROP INDEX [SAP_SCHEMA]."[TABLE]~BDLS";

So zum Beispiel der Index GLPCT~BDLS:

drop index saperp."GLPCT~BDLS";

Da die Indizes am ABAP vorbei direkt auf der Datenbank angelegt wurden erscheinen sie bei einer Prüfung der DB Objekte (TX DB02) in der Übersicht der Objekte, die auf der Datenbank existieren, aber nicht im ABAP DD (Data Dictionary) vorhanden sind.

About the author