SAP_Tips SAP_Tips Table of Contents 1. Performant programmieren................................................................................................................1 1.1 Vorwort....................................................................................................................................1 1.2 Open SQL................................................................................................................................1 1.3 Native SQL..............................................................................................................................3 2 Sammlung typischer (Performance−)Probleme und Lösungsvorschläge........................................4 2.1 Realisierung von Subqueries...................................................................................................4 2.2 Zugriffe auf logisch verknüpfte Tabellen................................................................................4 2.2.1 Geschachteltes SELECT.........................................................................................4 2.2.2 SELECT FOR ALL ENTRIES...............................................................................4 2.3 Portionsweises Einlesen..........................................................................................................6 2.4 Mengen Insert, Update, Delete................................................................................................6 2.4.1 Wie portionieren? Wann commit?..........................................................................6 2.4.2 Array−Update...........................................................................................................7 2.5 Existenzprüfung.......................................................................................................................7 2.6 ORDER BY versus ABAP Sort..............................................................................................7 2.7 DISTINCT versus ABAP SORT + DELETE ADJACENT DUPLICATES..........................8 2.8 Wann und wie Puffern?...........................................................................................................8 3 Tips & Tricks.........................................................................................................................................9 4 SQL Interface.......................................................................................................................................10 4.1 Projektion im Select..............................................................................................................10 4.2 Select ... Where vs. Select + Check.......................................................................................10 4.3 Select mit (Primär−)Index−Unterstützung............................................................................11 4.4 Select mit Buffer−Unterstützung..........................................................................................12 4.5 Select und Aggregatsfunktionen...........................................................................................13 4.6 Select mit ORDER BY vs. SORT.........................................................................................13 4.7 Existenzprüfung.....................................................................................................................14 4.8 Nutzung von Like/Between...................................................................................................15 4.9 Nutzung von RANGE/IN......................................................................................................16 4.10 Select single vs. Select−Endselect......................................................................................17 4.11 Select−Endselect vs. Array−Select.....................................................................................18 4.12 Select vs. Read....................................................................................................................19 4.13 Select und OR......................................................................................................................20 Select und OR........................................................................................................................................20 4.14 Select mit View...................................................................................................................21 4.15 Select mit View II...............................................................................................................21 4.16 Select mit FOR ALL ENTRIES..........................................................................................22 4.17 Select vs. OPEN CURSOR.................................................................................................23 4.18 Select vs. parallele CURSOR..............................................................................................25 4.19 Dynamischer vs. statischen SELECT..................................................................................26 4.20 Array−Insert vs. Einzelsatz−Insert......................................................................................27 4.21 Spalten−Update vs. klass. Update........................................................................................28 4.22 Select mit Unterabfrage (4.0)..............................................................................................28 4.23 Select mit INNER JOIN (4.0).............................................................................................30 4.24 Select mit LEFT OUTER JOIN (4.0)..................................................................................31 i SAP_Tips Table of Contents 5 Interne Tabellen...................................................................................................................................33 5.1 Interne Tabellen kopieren......................................................................................................33 5.2 Interne Tabellen vergleichen.................................................................................................34 5.3 Anhängen an eine Tabelle.....................................................................................................38 5.4 Aufbau von Tabellen ohne Dupletten...................................................................................39 5.5 Aufbau sortierter Tabellen....................................................................................................41 5.6 Aufbau von summierten Tabellen.........................................................................................43 5.7 Lineare Suche oder binary search..........................................................................................45 5.8 Versch. Arten von Schlüsselzugriffen...................................................................................46 5.9 Zweite Index−Tabelle...........................................................................................................47 5.10 Key Zugriffe auf mehrere Zeilen........................................................................................49 5.11 Explizite Arbeitsbereiche....................................................................................................51 5.12 Interne Tabellen sortieren....................................................................................................52 5.13 Interne Tabellen miteinander verknüpfen...........................................................................52 5.14 Geschachtelte LOOPs.........................................................................................................54 5.15 Modifizieren einzelner Komponenten.................................................................................57 5.16 Modifizieren mehrerer Zeilen.............................................................................................58 5.17 Einfügen einer int. Tab........................................................................................................60 5.18 Löschen mehrerer Zeilen.....................................................................................................61 5.19 Löschen eines Sets von Zeilen............................................................................................62 5.20 Bestimmte Tabelleneinträge zählen....................................................................................64 5.21 Großen Datenbestand filtern...............................................................................................65 5.22 Geschachtelte Tab. oder EXTRACT...................................................................................66 5.23 Anzahl Tabelleneinträge ermitteln......................................................................................69 5.24 Tabelle vom Typ SORTED (4.0)........................................................................................70 5.25 Tabelle vom Typ HASHED (4.0).......................................................................................71 6 String manipulation.............................................................................................................................74 6.1 Spezielle Operatoren im IF (CA, ...).....................................................................................74 6.2 String Verknüpfung...............................................................................................................74 6.3 String Verknüpfung II...........................................................................................................75 6.4 Trennen von Textstrings........................................................................................................76 6.5 Löschen führender Leerstellen..............................................................................................77 6.6 Nutzung strlen().....................................................................................................................78 6.7 Initialisierung.........................................................................................................................79 7 Typisierung...........................................................................................................................................80 7.1 Typisierte vs. nicht typ. Parameter........................................................................................80 7.2 Typisierte vs. nicht typ. Feldsymbole...................................................................................82 8 If, Case, 8.1 8.2 8.3 9 Field Conversion...................................................................................................................................86 9.1 Field Types I and P.................................................................................................................86 ....(Performance und Wartbarkeit).....................................................................................83 If vs. Case...............................................................................................................................83 While vs. Do...........................................................................................................................84 Case vs. Perform i Of ............................................................................................................84 ii SAP_Tips Table of Contents 9.2 9.3 9.4 9.5 Literals Type C and Type I....................................................................................................86 Konstanten vom Typ F..........................................................................................................87 Berechnungen.........................................................................................................................88 Gemischte Datentypen..........................................................................................................88 iii 1. Performant programmieren 1.1 Vorwort Dieses soll als Entscheidungshilfe, Handbuch und Checkliste bei der Analyse von Performance−Problemen dienen. Im folgenden werden zunächst kurz die wesentlichen Eigenschaften von Open SQL und Native SQL dargestellt. Beim Open SQL wird der Schwerpunkt auf die zu 4.0 neuen Möglichkeiten gelegt. Im weiteren werden konkrete Empfehlungen und Codierungsbeispiele für die Bereiche: 1. SQL−Interface 2. Interne Tabellen 3. String Manipulation 4. Allgemeine Hinweise (noch in Arbeit) 5. Typisierung 6. If; Case; performance und Wartbarkeit 7. Feldkonvertierung kurz beschrieben. In dieser Version wurden die Beispiele neu gruppiert, so daß zusammenhängende Beispiele nah aufgeführt sind. Für das Thema Parallel Cursor wurde ein passenderes Beispiel entwickelt. Einige Empfehlungen wurden verfeinert dargestellt. Anregungen, Verbesserungsvorschläge, Korrekturen und Nachfragen werden jederzeit gerne entgegengenommen. 1.2 Open SQL Die Open SQL Schnittstelle will Anwendungsentwickler(inne)n einen ausreichenden Sprachumfang an die Hand geben, der eine DB−unabhängige Entwicklung effizienter Anwendungen erlaubt. Diese Schnittstelle zeichnet sich aus durch: 1. Gute Integration in ABAP−Entwicklungsumgebung (Syntaxprüfung!). 2. Komfortable Datenausgabe und −übergabe über interne Tabellen, Zuordnung der Felder von SELECT−Klausel nach INTO−Klausel „by number“ und „by name“. 3. Alle Statements werden gegenüber der DB gleichartig aufbereitet. Dadurch entstehen wenige 1. Performant programmieren 1 SAP_Tips unterschiedliche Statements und der Statement Cache wird gut ausgenutzt. Die Funktionalität des Open SQL wurde durch verschiedene Erweiterungen in Richtung des ANSI/ISO Standards zu 3.0 erweitert. Hierzu gehört im wesentlichen: 1. Aggregatfunktionen (AVG, MAX, MIN, SUM, COUNT) sowie die GROUP BY Klausel. 2. Cursor Operationen (OPEN, FETCH, CLOSE). Hierdurch können parallel Cursor geöffnet werden und Zugriffe beliebig verschränkt durchgeführt werden. 3. Möglichkeit der Angabe von DISTINCT Dies erlaubt es, die Eindeutigkeit von Ergebnismengen vom DBS zu fordern und kann damit auch zu einer erheblichen Reduzierung der Datenmenge, die von der DB zum Applikations−Server transportiert werden, beitragen. ACHTUNG: DISTINCT erfordert Sortierungen auf dem DB−Server und ist daher relativ teuer, sofern kein Index verwendet werden kann. Anfragen mit DISTINCT können bei gepufferten Tabellen nicht auf dem Puffer abgewickelt werden und führen immer zu einem DB−Zugriff. Also: DISTINCT nur angeben, falls tatsächlich mit Duplikaten gerechnet werden muß (z.B. bei Projektions−Views) und diese nicht toleriert werden können. Bei einer drastischen Reduktion der zu transportierenden Datenmenge ist DISTINCT natürlich ebenfalls empfehlenswert. 4. Verwendung von Feldleisten im SELECT Es war bis zu Release 3.0 im OPEN SQL nicht möglich, einzelne Felder in der SELECT−Klausel anzugeben (nur SELECT *). Sollen nur wenige Felder selektiert werden, so ist eine Selektion mit '*' auf der DB−Tabelle nicht sinnvoll, da zu viele Daten unnötig transportiert werden. Bis zu Release 3.0 mußte in einem solchen Fall immer zunächst ein Projektions−View im Data Dictionary angelegt werden. Dies hatte den Zweck, die Anzahl unterschiedlicher Statements gering zu halten, um eine möglichst gute Trefferquote im Statement−Cache zu erhalten. Diese Technik sollte daher auch weiterhin soweit möglich beibehalten werden. Dort wo dies nicht möglich oder sinnvoll ist, können nun auch einzelne Felder beim SELECT ausgewählt werden. Um die Anzahl der Statements nicht durch vertauschte Feldreihenfolgen unnötig zu erhöhen, sollte sich die Reihenfolge immer am Dictionary orientieren. 5. INNER JOINS Joins sind erst mit 4.0 verfügbar. Unter 3.0. wird statt dessen entweder ein entsprechender View definiert oder die Subquery−Technik verwendet ( −> FOR ALL ENTRIES ) 1. Performant programmieren 2 SAP_Tips 1.3 Native SQL Die Native SQL Schnittstelle reicht alle Kommandos möglichst unverändert an das DBS weiter. Durch die weitgehende Umgehung der SAP−Datenbankschnittstelle ist hier die große Gefahr der Erzeugung von Inkonsistenzen bei der Durchführung von ändernden Operationen gegeben. Es erfolgt beispielsweise keine Tabellenprotokollierung, synchrone Matchcodes werden nicht aktualisiert und es findet auch keine Synchronisation mit dem SAP DB−Puffer statt. Hinzu kommt ein beträchtliches Potential von Portierungsproblemen. 1.3 Native SQL 3 2 Sammlung typischer (Performance−)Probleme und Lösungsvorschläge Dieser Abschnitt enthält eine Sammlung typischer Performance−Fallen und Lösungen dazu. 2.1 Realisierung von Subqueries 2.2 Zugriffe auf logisch verknüpfte Tabellen In diesem Abschnitt werden die verschiedenen Möglichkeiten vorgestellt und bewertet, wie auf logisch verknüpfte Tabellen zugegriffen werden kann. Der besseren Lesbarkeit wegen orientiert sich die Reihenfolge an der Release−Verfügbarkeit der einzelnen Techniken. 2.2.1 Geschachteltes SELECT Die einfachste und auch am weitesten verbreitete Möglichkeit, Daten aus logisch verknüpften Tabellen zu lesen, ist ein geschachteltes SELECT−Statement. Hierbei werden innerhalb einer SELECT−Schleife um die treibende Tabelle für jeden darin selektierten Satz einzelne SELECTS auf die abhängige(n) Tabelle(n) abgesetzt, um die anhängigen Sätze zu lesen: SELECT * FROM KNA1 [WHERE cond1]. SELECT * FROM KNB1 WHERE LIFNR = KNA1−LIFNR [AND cond2]. PERFORM DO_SOMETHING USING kna1 knb1. ENDSELECT. ENDSELECT. Der eklatante Nachteil dieser Lösung besteht darin, daß für jeden Satz, der in der äußeren SELECT−Schleife verarbeitet wird, ein SELECT gegen die Datenbank und damit u.U. auch über das Netz abgesetzt wird. Ist die von der äußeren Selektion bestimmte Treffermenge sehr groß, so entstehen in einer Client/Server Umgebung außerordentlich hohe Kommunikationskosten zwischen Applikations− und Datenbank−Server! Mit Release 3.0 stehen im Open SQL klar bessere Techniken zur Verfügung. 2.2.2 SELECT FOR ALL ENTRIES Das mit Release 3.0 neu in den Sprachumfang des Open SQL hinzugekommene SELECT−Konstrukt erlaubt eine mengenorientierte Verarbeitung gegenüber der Datenbank. Im Gegensatz zum geschachtelten SELECT, bei dem in der inneren SELECT−Schleife satzweise auf die Datenbank zugegriffen wird, ist es mit dem "SELECT FOR ALL ENTRIES" möglich, mehrere Sätze auf einmal von der Datenbank zu lesen. Das folgende Beispiel soll dies verdeutlichen: DATA: kna1_tab LIKE kna1 OCCURS 100 WITH HEADER LINE, knb1_tab LIKE knb1 OCCURS 1000 WITH HEADER LINE. 2 Sammlung typischer (Performance−)Probleme und Lösungsvorschläge 4 SAP_Tips SELECT * FROM kna1 INTO TABLE kna1_tab PACKAGE SIZE 100 [WHERE cond1]. SORT kna1_tab. SELECT * FROM knb1 INTO TABLE knb1_tab FOR ALL ENTRIES IN kna1_tab WHERE kunnr = kna1_tab−kunnr [AND cond2]. SORT knb1_tab. i = 0. LOOP AT kna1_tab. IF sy−tabix = 1. READ TABLE knb1_tab INDEX 1. ENDIF. WHILE sy−subrc = 0 AND kna1_tab−kunnr = knb1_tab−kunnr. PERFORM DO_SOMETHING USING kna1_tab knb1_tab. ADD 1 TO i. READ TABLE knb1_tab INDEX i. ENDWHILE. IF SY−SUBRC <> 0. EXIT. ENDIF. ENDLOOP. REFRESH kna1_tab. ENDSELECT. In der äußeren SELECT−Schleife wird die KNA1 portionsweise in eine interne Tabelle KNA1_TAB eingelesen und nach dem Primärschlüssel sortiert. Ob, wie in diesem Beispiel, mit ABAP−Mitteln sortiert wird (diese Sortierung findet auf dem Applikations−Server statt) oder aber mit Datenbankmitteln (in diesem Fall hätte die äußere SELECT−Schleife mit dem Zusatz ORDER BY PRIMARY KEY versehen werden müssen) hängt von der Einschränkung cond1 ab. Ein ORDER BY PRIMARY KEY ist nur dann zu empfehlen, wenn die Datenbank aufgrund der WHERE−Bedingung sowieso den Primärindex verwenden würde (z.B. bei einer Einschränkung über die Kundennummer: WHERE kunnr BETWEEN ... AND ...) und damit nicht explizit sortieren müßte. Wenn allerdings aufgrund der Bedingung cond1 die Abarbeitung der Selektion über einen Sekundärindex erfolgt, so wäre die Angabe des ORDER BY PRIMARY KEY kontraproduktiv, da dann die Datenbank die Ergebnismenge explizit sortieren müßte. Letzteres ist bei großen Datenmengen eine recht teure und CPU−intensive Operation, die die zentrale Resource "Datenbank−Server" unnötig belasten würde. Für jede der in der äußeren SELECT−Schleife in die interne Tabelle KNA1_TAB gelesene Datenportion werden alle zugehörigen abhängigen Sätze über den SELECT FOR ALL ENTRIES mit einem (bzw. wenigen − s.u.) Datenbankzugriffen in die interne Tabelle KNB1_TAB eingelesen. Um die beiden internen Tabellen KNA1_TAB und KNB1_TAB danach effizient abmischen zu können, ist es sinnvoll auch die KNB1_TAB zu sortieren, um dann in einem geschachtelten Loop die gewünschte Verarbeitung auszuführen. Die Größe der bei einem SELECT FOR ALL ENTRIES angegeben internen Tabelle ist im Prinzip nicht limitiert. Allerdings ist zu beachten, daß die Umsetzung des SELECT FOR ALL ENTRIES in SQL−Syntax durch die Datenbankschnittstelle zu einer Veroderung (bei manchen Datenbanksystemen Unionbildung) der WHERE−Bedingung für jede Zeile der internen Tabelle führt. So würde z.B. obiges SELECT FOR ALL ENTRIES in folgendes SQL−Statement transformiert: SELECT * FROM knb1 WHERE kunnr = kna1_tab−kunnr[1] [AND cond2] 2 Sammlung typischer (Performance−)Probleme und Lösungsvorschläge 5 SAP_Tips OR kunnr = kna1_tab−kunnr[2] [AND cond2] ... OR kunnr = kna1_tab−kunnr[100] [AND cond2]. Wie man sieht, können abhängig von der Größe der internen Tabelle sehr komplexe SQL−Statements entstehen. Die Datenbankschnittstelle zerlegt ein solches komplexes Statement abhängig von der Größe der internen Tabelle (teilweise sogar von der Breite der in der WHERE−Bedingung verwendeten Felder) in mehrere einzelne Statements, die den Restriktionen des jeweiligen Datenbanksystems gerade noch genügen, und vereinigt dann die Ergebnisse der Einzelstatements. Duplikate werden dabei vom ABAP eliminiert. Die Angabe einer Aggregatfunktion ist im Zusammenhang mit dem FOR ALL ENTRIES Zusatz unsinnig! 2.3 Portionsweises Einlesen Wenn portionsweise Daten eingelesen werden sollen, dann müssen zwei Fälle unterschieden werden: · Einlesen geschieht innerhalb einer Transaktion. In diesem Fall kann das Einlesen mit Hilfe des SELECT Zusatzes PACKAGE SIZE reguliert werden. Das Ergebnis der Selektion wird in eine interne Tabelle gestellt. · Bildwechsel oder sonstige Transaktionsbeendigung erforderlich. Ein Beispiel wäre hier das portionsweise Anzeigen und Weitersuchen nach Interaktion mit dem Benutzer oder auch der Fall, daß Portionen von Daten mit einem RFC verarbeitet werden sollen. In einem solchen Fall müssen die Daten mit dem SELECT−Zusatz "UP TO n ROWS" eingelesen werden. Der letzte erhaltene Key wird gemerkt und dann zum Wiederaufsetzen verwendet. Voraussetzung ist dabei natürlich, daß sortiert gelesen wird. 2.4 Mengen Insert, Update, Delete 2.4.1 Wie portionieren? Wann commit? Das Durchführen großer Mengen von Änderungsoperationen erfordert vom DBS das Schreiben/Verwalten von großen Datenmengen, um ein Rücksetzen (Rollback) der durchgeführten Operationen jederzeit zu ermöglichen. Der hierfür benötigte Speicher kann dabei zu einem Engpaß werden (z.B. Rollback−Segment−Überlauf) oder auch die maximale Anzahl von Sperr−einträgen (Lock−Table Überlauf). Es muß daher dafür gesorgt werden, daß die Änderungsoperationen in bestimmten Abständen bestätigt (Committed) werden. Ein Rücksetzen vor einen solchen Commit−Zeitpunkt ist dann aber nicht mehr automatisch möglich. Es muß vielmehr ein Wiederaufsetzmechanismus vorgesehen werden, der die bereits durchgeführten Änderungen berücksichtigt. 2.3 Portionsweises Einlesen 6 SAP_Tips Eine typische Größe für ORACLE Rollback−Segmente im SAP Umfeld beträgt etwa 100MB. Diese Grenze sollte jedoch nie voll ausgeschöpft werden, da auch die Daten für Änderungen anderer Prozesse im gleichen ROLLBACK−Segment gesichert werden könnten. Die Verwendung eines Task−Handler−Commit Aufrufes (COMMIT WORK) bringt den Nachteil mit sich, daß ein Prozeßwechsel stattfinden kann und daher alle geöffneten Cursor geschlossen werden müssen. Aus diesem Grund wird ab 3.0 ein spezieller Funktionsbaustein zur Durchführung von Datenbank−Commits angeboten: CALL FUNCTION 'DB_COMMIT'. WICHTIG: Bei Selektionen, die nach dem Commit fortgeführt werden sollen, muß der Cursor mit dem Zusatz WITH HOLD eröffnet werden ! 2.4.2 Array−Update Sind wenige Felder in vielen Sätzen zu ändern, so geschieht dies am besten durch die Definition einer (Update−fähigen) View über die Schlüsselfelder und die Felder, die geändert werden sollen. Die gleiche Technik kann übrigens auch beim INSERT angewandt werden, wenn viele Felder mit dem Initialwert belegt werden sollen. Es ist dann aber darauf zu achten, daß die fraglichen Spalten mit NOT NULL im Dictionary stehen. 2.5 Existenzprüfung SELECT * FROM dbtab UP TO 1 ROWS WHERE (Bedingung). ENDSELECT. IF sy−subrc EQ 0. exists = 'TRUE'. ENDIF. Ab Release 3.0 kann auch anstatt '*' ein einzelnes Feld angegeben werden, um die Menge der transportierten Daten zu reduzieren. Bei der Verwendung von Feldern ist jedoch wie immer zu berücksichtigen, daß dadurch die Anzahl der verschiedenen Statements steigt und die Trefferrate im Statement−Cache sinken kann. Von der Verwendung von COUNT(*) ist abzuraten, da in diesem Fall von der DB die gesamte Treffermenge zusammengestellt werden muß. Bei Oracle kommt noch erschwerend hinzu, daß dabei in dem Falle, daß keine WHERE−Bedingung angegeben ist, über die Daten anstatt (wie es vernünftig wäre) über den Index gegangen wird. 2.6 ORDER BY versus ABAP Sort Um den DB−Server zu entlasten, ist i.a. Sortieren im ABAP vorzuziehen. Es ist zu beachten, daß das Sortieren großer Datenmengen auf dem DB−Server Auswirkungen auf die Performance aller Anwender hat, während das Sortieren im ABAP nur den jeweiligen Applikations−Server in 2.4.2 Array−Update 7 SAP_Tips die Knie zwingt. Kann allerdings für die Sortierung ein Index verwendet werden, so entstehen auf DB−Seite kaum zusätzliche Kosten für die Sortierung. 2.7 DISTINCT versus ABAP SORT + DELETE ADJACENT DUPLICATES Wenn DISTINCT die Ergebnismenge deutlich einschränkt, dann ist die Verwendung in Select vorzuziehen. Distinct macht aber nur Sinn auf Views, die nicht über den kompletten Primärschlüssel verfügen. Ansonsten ist die Ergebnismenge ohnehin eindeutig. Erstellung von Statistiken 2.8 Wann und wie Puffern? Das Puffern von Tabellen erhöht in vielen Fällen die Lesegeschwindigkeit. Die Angabe von genauen Zahlenwerten hier ist nicht unproblematisch, da die Systembelastung eine gewaltige Rolle spielt. Außerdem ist zu berücksichtigen, ob eine Tabelle extra für den Lesezugriff in den Puffer geladen werden muß oder ob sie sich schon darin befindet. Bei den Werten für den DB Zugriff ist entscheidend, ob Platten I/O erforderlich ist oder nicht. Für ein eingeschwungenes, mittelmäßig belastetes System, bei dem sich also die Daten bereits im Puffer befinden, muß für das Lesen eines Satzes − SELECT SINGLE − einer gepufferten Tabelle mit ca. 0,2 ms gerechnet werden, während für das Lesen auf ungepufferten Tabellen mit ca. 5 ms gerechnet werden muß. 2.7 DISTINCT versus ABAP SORT + DELETE ADJACENT DUPLICATES 8 3 Tips & Tricks Die konkreten Beispiele können durch den Tester/Entwickler temporär modifiziert werden. Nach dem Verlassen der TRX gehen die Änderungen verloren. In den folgenden Kapiteln sind die Beispiele aus „Tips & Tricks“ dokumentiert. Die Überschriften entsprechen den Auswahlmöglichkeiten. Anmerkungen: · Das Kapitel „Allgemeine Hinweise“ ist noch in Entwicklung. · Beispiele werden ständig verbessert bzw. erweitert · Bei einem Neuaufbau des CF3 müssen bestimmte Beispieltabellen ggf. erst initialisert werden. · SFLIGHT, CUSTOMERS · Mit der Bereitstellung DM2 wird die Entwicklung und Pflege von Tips & Tricks in diesem System durchgeführt. 3 Tips & Tricks 9 4 SQL Interface 4.1 Projektion im Select Select * SELECT * FROM VZZKOKO WHERE BUKRS = '0020' AND SANLF = '300' AND RKEY1 = '0001821840011'. ENDSELECT. Select mit Feldliste SELECT DGUEL_KK BZUSAGE FROM VZZKOKO INTO CORRESPONDING FIELDS OF VZZKOKO WHERE BUKRS = '0020' AND SANLF = '300' AND RKEY1 = '0001821840011'. ENDSELECT. Bewertung Falls nur einige Spalten einer Tabelle benötigt werden, nutzen Sie entweder einen VIEW oder geben Sie die Feldliste im Select an. Je mehr Treffer (z.B. VDBEKI zu einem Darlehen) desto größer der Performancegewinn. 50% der Felder eingelesen > ca. 40% Zugriffszeit gespart −> Views z.Zt ZZVBEKI, ZZVBEKI2, ZZVBEKIALL, VDBEVI 4.2 Select ... Where vs. Select + Check Select + Check SELECT * FROM VDBEKI WHERE BUKRS = '0020' 4 SQL Interface 10 SAP_Tips AND RANL = '0000012310014'. CHECK VDBEKI−DBUDAT = '16.06.1997'. ENDSELECT. Select mit Where Bedingung SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014' AND DBUDAT = '16.06.1997'. ENDSELECT. Bewertung Bekannte Bedingungen sollten in der WHERE−Bedingung angegeben werden. Dies ist meist performanter als die Prüfung innerhalb Select−Endselect mit CHECK. Die Datenbank kann dann einen passenden Index nutzen. Beachten Sie vorhandene Indizes bei der Formulierung eines Selects. Die Reihenfolge der Felder in der WHERE−Bedingung sollte die Reihenfolge des Index widerspiegeln. −> Indizes zu einer Tabelle via se12 4.3 Select mit (Primär−)Index−Unterstützung Select mit Schlüssellücke SELECT * FROM VDARL WHERE BUKRS AND RANL = '0020' = '0000012310014'. ENDSELECT. Select ohne Lücke im (Primär−)Index SELECT * FROM VDARL WHERE BUKRS AND SARCHIV AND RANL 4.3 = '0020' ='' = '0000012310014'. Select mit (Primär−)Index−Unterstützung 11 SAP_Tips ENDSELECT. Bewertung Für häufig genutzte Zugriffe muß stets versucht werden, einen Index zu nutzen. Zugriffe mit Teilschlüsseln sind immer dann nicht performant, wenn die Lücke vor dem entscheidenden Kriterium ist: Beispiel: VDARL:Nach BUKRS hat der Index noch nichts eingrenzen können, es sind noch alle 145.000 Sätze relevant. −> damit müssen im schlechtesten Fall alle Eintragungen durchsucht werden. 4.4 Select mit Buffer−Unterstützung Select auf ungepuffterte Tab. SELECT SINGLE * FROM T100 BYPASSING BUFFER WHERE SPRSL = 'D' AND ARBGB = '00' AND MSGNR = '999'. Select mit gepufferter Tab. SELECT SINGLE * FROM T100 WHERE SPRSL = 'D' AND ARBGB = '00' AND MSGNR = '999'. Bewertung Häufig genutzte Customizing−Tabellen sollten gepuffert werden. −> z.B. für Online−Anwendungen Stamm− und Bewegungsdaten werden nicht im SAP−Umfeld gepuffert. In Batch−Programmen −> Tabelle einmal in interne Tabelle −> READ BINARY SEARCH Folgende Zusätze zum SELECT verhindern einen Zugriff auf den Puffer: FOR UPDATE, ORDER BY (verschieden vom Primärschlüssel), COUNT, AVG, MAX, MIN, SUM, DISTINCT, IS NULL, native SQL ... . 4.4 Select mit Buffer−Unterstützung 12 SAP_Tips 4.5 Select und Aggregatsfunktionen Select ... Where + Check C4A = '000'. SELECT * FROM T100 WHERE SPRSL = 'D' AND ARBGB = '00'. CHECK: T100−MSGNR > C4A. C4A = T100−MSGNR. ENDSELECT. Select mit Aggregatsfunktion SELECT MAX( MSGNR ) FROM T100 INTO C4A WHERE SPRSL = 'D' AND ARBGB = '00'. Bewertung Diese Zugriffe bringen nur dann einen Performancevorteil, wenn ausschließlich z.B. die Anzahl von Sätzen oder die Summe einer Tabellenspalte benötigt wird und nicht aber die eigentlichen Daten aus der Tabelle. . 4.6 Select mit ORDER BY vs. SORT Select mit Order BY SELECT * FROM VDBEKI INTO TABLE I_VDBEKI WHERE BUKRS = '0020' AND RANL < '000000200000' ORDER BY DBLDAT. Select mit SORT SELECT * FROM VDBEKI INTO TABLE I_VDBEKI WHERE BUKRS = '0020' 4.5 Select und Aggregatsfunktionen 13 SAP_Tips AND RANL < '000000200000'. SORT I_VDBEKI BY DBLDAT. Bewertung Ein ORDER BY ist nur dann zu empfehlen, wenn die Datenbank aufgrund der WHERE−Bedingungen den gleichen Index verwendet und damit nicht explizit sortieren müßte. Letzeres ist bei großen Datenmengen eine recht teure und CPU−intensive Operation, die die zentrale Resource Datenbankserver unnötig belasten würde. Warnung: ORDER BY verschieden vom Primärschlüssel geht immer am SAP−Puffer vorbei ! 4.7 Existenzprüfung Select UP TO 1 ROWS SELECT * FROM VDBEKI UP TO 1 ROWS WHERE BUKRS = '0020' AND RANL = '0000012310014'. ENDSELECT. IF SY−SUBRC = 0. " exists = 'TRUE'. ENDIF. Select mit Exit SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014'. EXIT. ENDSELECT. IF SY−SUBRC = 0. " exists = 'TRUE'. ENDIF. 4.7 Existenzprüfung 14 SAP_Tips Bewertung Zum Überprüfen der Existenz mindestens eines Datensatzes zur angegebenen WHERE−Be−dingung auf einer DB−Tabelle, sollte der Konstrukt mit UP to 1 ROWS verwandt werden. Im Falle der Existenz ist dieser wesentlich schneller. Ab 3.0 kann ein SELECT SINGLE auch mit Teilschlüssel benutzt werden. Select ... Into Table t Select + Append statement REFRESH I_VDBEKI. SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014'. APPEND I_VDBEKI. ENDSELECT. Select Into Table SELECT * FROM VDBEKI INTO TABLE I_VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014'. Bewertung Into Table ist immer schneller als die Nutzung von Append im Select−Endselect−loop. Beim SELECT ... INTO TABLE itab mit dem Zusatz PACKAGE SIZE n werden nicht alle selektierten Zeilen auf einmal in die interne Tabelle gestellt, sondern in Paketen von n Zeilen. Der Inhalt von itab wird von jedem neuen Paket überschrieben. So kann vermieden werden, daß die interne Tabelle zu groß wird. 4.8 Nutzung von Like/Between Select mit LIKE SELECT * FROM VDBEPP WHERE BUKRS AND RANL 4.8 = '0020' LIKE '000001231%'. Nutzung von Like/Between 15 SAP_Tips ENDSELECT. Select mit BETWEEN SELECT * FROM VDBEPP WHERE BUKRS = '0020' AND RANL BETWEEN '0000012310000' AND '0000012319999'. ENDSELECT. Bewertung Die Nutzung von LIKE ist in vielen Fällen weniger performant als die Verwendung vom BETWEEN. Auch hier wird im SQL−Trace eine größere Differenz angezeigt. 4.9 Nutzung von RANGE/IN Notwendiger Vorlauf für Beispiel REFRESH RANGE_VDARL. RANGE_VDARL−SIGN = 'I'. RANGE_VDARL−OPTION = 'EQ'. SELECT * FROM VDARL UP TO 100 ROWS WHERE BUKRS ='0020'. RANGE_VDARL−LOW = VDARL−RANL. APPEND RANGE_VDARL. ENDSELECT. Select mit RANGE SELECT * FROM VDARL WHERE BUKRS = '0020' AND SARCHIV = ' ' AND RANL 4.9 IN RANGE_VDARL. Nutzung von RANGE/IN 16 SAP_Tips ENDSELECT. Notwendiger Vorlauf für Beispiel REFRESH RANGE_VDARL. RANGE_VDARL−SIGN = 'I'. RANGE_VDARL−OPTION = 'EQ'. SELECT * FROM VDARL UP TO 100 ROWS WHERE BUKRS ='0020'. RANGE_VDARL−LOW = VDARL−RANL. APPEND RANGE_VDARL. ENDSELECT. Select Single im LOOP LOOP AT RANGE_VDARL. SELECT SINGLE * FROM VDARL WHERE BUKRS = '0020' AND SARCHIV = ' ' AND RANL = RANGE_VDARL−LOW. ENDLOOP. Bewertung Die Tabelle Range_vdarl hat 100 Eintragungen. Die Nutzung von Range ist hier günstiger Achtung: Auch die Oracle−Version unter 3.0 verträgt nur max. 255 Einträge. 4.10 Select single vs. Select−Endselect Select−Endselect SELECT * FROM VDARL WHERE BUKRS AND SARCHIV AND RANL 4.10 = '0020' ='' = '0000012310014'. Select single vs. Select−Endselect 17 SAP_Tips ENDSELECT. Select single SELECT SINGLE * FROM VDARL WHERE BUKRS = '0020' AND SARCHIV AND RANL ='' = '0000012310014'. Bewertung Falls alle Felder des Primärindex bekannt sind, sollte ein Select Single genutzt werden. Der Select Single benötigt genau eine Kommunikation mit dem Datenbank−Server, der Select−Endselect dagegen zwei. 4.11 Select−Endselect vs. Array−Select Select Into Table t + Loop at t. SELECT * FROM VDBEKI INTO TABLE I_VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014'. LOOP AT I_VDBEKI. ENDLOOP. LOOP AT I_VDBEKI. ENDLOOP. Select ... Endselect. SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0001821840011'. ENDSELECT. SELECT * FROM VDBEKI WHERE BUKRS = '0020' 4.11 Select−Endselect vs. Array−Select 18 SAP_Tips AND RANL = '0001821840011'. ENDSELECT. Bewertung Falls Sie Daten mehrfach nutzen müssen, bringt die Nutzung der internen Tabelle einen Performancevorteil. Bei großen Tabellen wächst der Page−Bereich des Programms an. Selbst wenn die Verarbeitung nur einmal erfolgt, ist ein nicht unerheblicher Vorteil meßbar (2. Loop und 2. Select aussternen) 4.12 Select vs. Read Select vs. Read für Customizing−Tabellen Select Single DO 1000 TIMES. SELECT SINGLE * FROM TZK0A WHERE SPRAS ='D' AND RANTYP = '1' AND SKOART = '0920'. ENDDO. Read Binary Search SELECT * FROM TZK0A INTO TABLE I_TZK0A. SORT I_TZK0A BY MANDT SPRAS RANTYP SKOART. DO 1000 TIMES. KEY−MANDT = '001'. KEY−SPRAS = 'D'. KEY−RANTYP = '1'. KEY−SKOART = '0920'. READ TABLE I_TZK0A WITH KEY KEY BINARY SEARCH. ENDDO. Bewertung 4.12 Select vs. Read 19 SAP_Tips Read binary Search ist besonders für Programme zu empfehlen, die einen größeren Bestand auswerten. Für Online−Trx. ist das Select Single im Vorteil. Batch: −> Einmaliges Einlesen der gesamten TZK0A : ca. 90 msec. −> Lesen Kondition aus interner Tabelle (für unterschiedliche Konditionsarten) −> In diesem Fall wird ein größerer Performancevorteil im Vergleich zum Select single erreicht. 4.13 Select und OR Select und OR Klassischer OR SELECT * FROM TZK01 WHERE SKOAREF = '0000' AND ( SBEWZITI = 'KEIG' OR SBEWZITI = 'TBB' ). ENDSELECT. Aufgelöster OR SELECT * FROM TZK01 WHERE ( SKOAREF = '0000' AND SBEWZITI = 'KEIG' ) OR ( SKOAREF = '0000' AND SBEWZITI = 'TBB' ). ENDSELECT. Bewertung Beide Bsp. liefern das gleiche Ergebnis. Tabelle hat 223 Einträge (Konditionsarten) Empfehlungen zu kompliziert aufgebauten OR−Klauseln müssen nicht in jedem Fall schneller sein. Jedoch ist bei größeren Tabellen und selektiv gehaltenen Feldern die rechte Seite schneller. 4.13 Select und OR 20 SAP_Tips 4.14 Select mit View Geschachtelte Select−Statements SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014'. SELECT * FROM VDBEPI WHERE BUKRS = '0020' AND = VDBEKI−RBELKPFD. RBELKPFD ENDSELECT. ENDSELECT. Select mit View SELECT * FROM ZZVBEKIALL WHERE BUKRS = '0020' AND RANL = '0000012310014'. ENDSELECT. Bewertung Die Nutzung eines Views ist immer einem geschachtelten Select−statement vorzuziehen. Selbst bei identischer Feldanzahl ist der View schneller Der View ZZVBEKI2 hat weniger Felder als ZZVBEKIALL. Der Performancegewinn zum Gesamtview ist beachtlich (ca. 50 %). Test Sie selbst in Tips und Tricks. Auch der View VDBEVI bringt Performancegewinn. −> Datenbankviews (Typ D) finden Sie über se12 oder se15 Z.Zt: ZZVBEKI, ZZVBEKI2, ZZVBEKIALL und VDBEVI −> Zum Pflege der Customizing−Tabellen gibt es Pflege−Views 4.15 Select mit View II Vollständiger Index SELECT * FROM ZZVBEKIALL 4.14 Select mit View 21 SAP_Tips WHERE BUKRS = '0020' AND RANL = '0000012310014' AND SANLF = '300'. ENDSELECT. letztes Indexfeld fehlt SELECT * FROM ZZVBEKIALL WHERE BUKRS = '0020' AND RANL = '0000012310014'. ENDSELECT. Bewertung Die Indizes der Basistabellen werden auf den View übertragen. Die vollständige Angabe der Indexfelder ist performanter. Der Effekt tritt bei Views mit geringer Feldanzahl stärker auf z.B. ZZVBEKI2 4.16 Select mit FOR ALL ENTRIES Geschachtelter Select SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014'. SELECT * FROM VDBEPI WHERE BUKRS = '0020' AND = VDBEKI−RBELKPFD. RBELKPFD ENDSELECT. ENDSELECT. Select mit FOR ALL ENTRIES SELECT * FROM vdbeki into table i_vdbeki WHERE BUKRS = '0020' AND RANL = '0000012310014'. 4.16 Select mit FOR ALL ENTRIES 22 SAP_Tips IF SY−DBCNT > 0. SELECT * FROM VDBEPI FOR ALL entries in i_vdbeki where bukrs = '0020' and rbelkpfd = i_vdbeki−rbelkpfd. ENDSELECT. ENDIF. Bewertung Liegt kein DB−View vor, ist die Lösung mit FOR ALL ENTRIES vorzuziehen. Vor allem dann, wenn der Inhalt der internen Tabelle i_vdbeki noch weiter verwendet werden soll. Die 2.Select−Schleife mit dem Zusatz FOR ALL ENTRIES ist im Vgl. mit einer LOOP−SELECT−SINGLE−Lösung ebenfalls performanter, siehe Beispiel 'Nutzung RANGE/IN'. Der Zusatz FOR ALL ENTRIES kann auch mit dem Zusatz INTO TABLE, also mit einem Array−Fetch verwandt werden. Alternativen: Siehe Beispiele 'Select mit View', 'parallele CURSOR' . * Das Verhalten des SELECT FOR ALL ENTRIES kann mit Profilparametern beeinflußt werden. Eine vernünftige Kombination dieser Parameter wäre: rsdb/max_blocking_factor = 40 rsdb/min_blocking_factor = 5 rsdb/max_in_blocking_factor = 250 rsdb/min_in_blocking_factor = 40 Änderungen sollten mit dem Systemadministrator abgesprochen werden, da sie das gesamte R/3−System betreffen ! * 4.17 Select vs. OPEN CURSOR select vs. OPEN CURSOR DATA C1 TYPE CURSOR. DATA D1 TYPE CURSOR. Mit OPEN CURSOR OPEN CURSOR C1 FOR SELECT * FROM VDBEKI 4.17 Select vs. OPEN CURSOR 23 SAP_Tips WHERE BUKRS = '0020' AND RANL = '0000012310014'. DO. FETCH NEXT CURSOR C1 INTO VDBEKI. IF SY−SUBRC <> 0. CLOSE CURSOR C1. EXIT. ENDIF. OPEN CURSOR D1 FOR SELECT * FROM VDBEPI WHERE BUKRS = '0020' AND RBELKPFD = VDBEKI−RBELKPFD. DO. FETCH NEXT CURSOR D1 INTO VDBEPI. IF SY−SUBRC <> 0. CLOSE CURSOR D1. EXIT. ENDIF. ENDDO. ENDDO. Klassischer Select SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0000012310014'. SELECT * FROM VDBEPI WHERE BUKRS = '0020' AND RBELKPFD = VDBEKI−RBELKPFD. ENDSELECT. ENDSELECT. Bewertung Das obige Konstrukt mit der eigenen CURSOR−Verwaltung ist ähnlich unperformant wie der geschachtelte SELECT, da immer wieder der CURSOR der inneren Tabelle geöffnet werden muß. Alternativen dazu sind das Lesen über einen DB−VIEW, der SELECT mit FOR ALL ENTRIES oder die parallele 4.17 Select vs. OPEN CURSOR 24 SAP_Tips CURSOR−Definition (siehe Beispiele). * Generell gilt für die Performanz zum Lesen abhängiger Tabellen: * Selektivität des äußeren SELECTs: niedrig mittel hoch −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− geschachtelter SELECT (klassisch) − o SELECT mit FOR ALL ENTRIES parallele CURSOR + + o o + o − (+:gute o:mittlere −:schlechte Performanz) Kann kein DB−View angelegt werden (z.B. wegen redundanter Datenhaltung etc. ), dann stellt die Lösung mit SELECT FOR ALL ENTRIES in allen Fällen einen guten Kompromiß dar. 4.18 Select vs. parallele CURSOR select vs. parallele CURSOR DATA C1 TYPE CURSOR. DATA C2 TYPE CURSOR. Mit parallele CURSOR OPEN CURSOR C1 FOR SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RBELKPFD BETWEEN '0000001500' AND '0000001550' ORDER BY PRIMARY KEY. OPEN CURSOR C2 FOR SELECT * FROM VDBEPI WHERE BUKRS = '0020' ORDER BY PRIMARY KEY. DO. FETCH NEXT CURSOR C1 INTO VDBEKI. IF SY−SUBRC <> 0. CLOSE CURSOR C1. EXIT. ENDIF. 4.18 Select vs. parallele CURSOR 25 SAP_Tips IF SY−INDEX = 1. FETCH NEXT CURSOR C2 INTO VDBEPI. ENDIF. WHILE SY−SUBRC = 0 AND VDBEKI−RBELKPFD = VDBEPI−RBELKPFD. FETCH NEXT CURSOR C2 INTO VDBEPI. ENDWHILE. IF SY−SUBRC <> 0. CLOSE CURSOR C2. EXIT. ENDIF. ENDDO. Klassischer Select SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RBELKPFD BETWEEN '0000001500' AND '0000001550'. SELECT * FROM VDBEPI WHERE BUKRS = '0020' AND RBELKPFD = VDBEKI−RBELKPFD. ENDSELECT. ENDSELECT. Bewertung Vorteil der parallelen Cursor: Auf die innere Tabelle wird nur einmal eine OPEN CURSOR abgesetzt. Nachteil: Einschränkung der übergeordneten Tabelle kann nicht auf die untergeordnete weitergegeben werden. Folgerung: Je selektiver die Bedingung in der übergeordneten Tabelle ist, um so mehr überwiegt der Nachteil. Im obigen Beispiel überwiegt der Vorteil, siehe auch Testprogramm ZSTEST07. 4.19 Dynamischer vs. statischen SELECT DATA: TAB_NAME(10). DATA: WA LIKE VDBEKI. Dynamischer SELECT TAB_NAME = 'VDBEKI'. 4.19 Dynamischer vs. statischen SELECT 26 SAP_Tips SELECT * FROM (TAB_NAME) INTO WA WHERE BUKRS = '0020' AND RBELKPFD BETWEEN '0000001500' AND '0000001550'. ENDSELECT. Klassischer Select SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RBELKPFD BETWEEN '0000001500' AND '0000001550'. ENDSELECT. Bewertung Angabe des Namens der Datenbanktabelle oder des Views zur Laufzeit bei den Aufrufen von SELECT, INSERT, UPDATE, MODIFY und DELETE. * Der Name einer Datenbanktabelle oder eines Views kann als Inhalt eines Feldes und somit dynamisch angegeben werden. Diese dynamische Angabe des Tabellennamens im Quelltext ist in der Regel unperformanter als die statische, da interne Kontrollblöcke erst zur Laufzeit generiert werden können. * 4.20 Array−Insert vs. Einzelsatz−Insert DATA: TAB LIKE SFLIGHT OCCURS 100 WITH HEADER LINE. SELECT * FROM SFLIGHT INTO TABLE TAB. DELETE SFLIGHT FROM TABLE TAB. Einzelzeilen Inserts LOOP AT TAB. INSERT INTO SFLIGHT VALUES TAB. ENDLOOP. DATA: TAB LIKE SFLIGHT OCCURS 100 WITH HEADER LINE. SELECT * FROM SFLIGHT INTO TABLE TAB. DELETE SFLIGHT FROM TABLE TAB. Array−Insert 4.20 Array−Insert vs. Einzelsatz−Insert 27 SAP_Tips INSERT SFLIGHT FROM TABLE TAB. Bewertung Die Summe von n Einzel−Inserts benötigt immer mehr Zeit als ein einmaliger Insert von n Tabellen−Zeilen. Dieser Massen−Update durch den Zusatz FROM TABLE ist auch möglich für UPDATE, DELETE und MODIFY. Der Performanzgewinn geht aber im Falle des MODIFYs verloren. Um obiges Beispiel zu testen, sollte die Demo−Tabelle SFLIGHT mit dem Report RSBCDAT1 gefüllt worden sein. Mit diesen Daten ist der Array−Insert im obigen Beispiel 8 mal schneller. 4.21 Spalten−Update vs. klass. Update UPDATE SFLIGHT SET SEATSOCC = SEATSOCC + 1. Einzelzeilen Updates SELECT * FROM SFLIGHT. SFLIGHT−SEATSOCC = SFLIGHT−SEATSOCC − 1. UPDATE SFLIGHT. ENDSELECT. UPDATE SFLIGHT SET SEATSOCC = SEATSOCC + 1. Spalten−Update UPDATE SFLIGHT SET SEATSOCC = SEATSOCC − 1. Bewertung Falls nur wenige Spalten einer Tabelle verändert werden sollen, ist die Nutzung des Spalten−Update vorzuziehen. Um obiges Beispiel zu testen, sollte die Demo−Tabelle SFLIGHT mit dem Report RSBCDAT1 gefüllt worden sein. Mit diesen Daten ist der Spalten−Update im obigen Beispiel 6 mal schneller. 4.22 Select mit Unterabfrage (4.0) Geschachtelter Select SELECT * FROM VDARL WHERE BUKRS = '0020' AND SARCHIV = ' ' AND RANL BETWEEN '0003000100000' AND 4.21 Spalten−Update vs. klass. Update 28 SAP_Tips '0003000200000' . SELECT * FROM VDBEPP WHERE BUKRS = VDARL−BUKRS AND RANL = VDARL−RANL AND DTRANS < '19950101'. WRITE: / vdarl−ranl. ENDSELECT. ENDSELECT. Select mit Unterabfrage SELECT * FROM VDARL AS F1 WHERE BUKRS = '0020' AND SARCHIV = ' ' AND RANL BETWEEN '0003000100000' AND '0003000200000' AND RANL IN ( SELECT RANL FROM VDBEPP WHERE BUKRS = F1~BUKRS AND RANL = F1~RANL AND DTRANS < '19950101' ) . WRITE: / vdarl−ranl. ENDSELECT. Bewertung So können Sie komplexe Abfragen effizient programmieren. In der ersten Anweisung werden alle Daten von der Datenbank an die Anwendung übergeben, wo sie dann gefiltert werden. In der zweiten Anweisung werden die Daten in der Datenbank gefiltert, wobei ein Alias verwendet werden muß. Dies bedeutet aber, daß weniger Daten von der Datenbank an die Anwendung übergeben werden müssen. Diese Methode hat gegenüber der normalen SELECT−Anweisung einige Einschränkungen, z.B. kein SELECT SINGLE. 4.21 Spalten−Update vs. klass. Update 29 SAP_Tips 4.23 Select mit INNER JOIN (4.0) Geschachtelter Select SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0002000500010'. SELECT * FROM VDBEPI WHERE BUKRS = '0020' AND = VDBEKI−RBELKPFD. RBELKPFD WRITE: / vdbeki−bukrs, vdbeki−rbelkpfd, vdbepi−dfaell. ENDSELECT. ENDSELECT. INNER JOIN SELECT F1~BUKRS F1~RBELKPFD F2~DFAELL INTO (VDBEKI−BUKRS, VDBEKI−RBELKPFD, VDBEPI−DFAELL) FROM VDBEKI AS F1 INNER JOIN VDBEPI AS F2 ON F1~BUKRS = F2~BUKRS AND F1~RBELKPFD = F2~RBELKPFD WHERE F1~BUKRS = '0020' AND F1~RANL = '0002000500010'. WRITE: / vdbeki−bukrs, vdbeki−rbelkpfd, vdbepi−dfaell. ENDSELECT. Bewertung Bei einem inneren Join legt das System eine temporäre Tabelle an, die die Kombinationen der Zeilen der Datenbanktabellen enthält, deren Werte die mit ON <condition> angegebene logische Bedingung erfüllt eine Ergebnismenge. Es ist unerheblich, ob die Bedingung in der ON− oder in der WHERE−Klausel angegeben wird; das Ergebnis eines inneren Join ist dasselbe. Wenn Sie in der Feldliste Feldnamen verwenden, die in beiden Tabellen eines inneren Join vorkommen, 4.23 Select mit INNER JOIN (4.0) 30 SAP_Tips müssen Sie sie eindeutig machen, indem Sie ihnen einen Aliasnamen und eine Tilde voranstellen. Sie geben den Aliasnamen in der FORM−Klausel mit dem Zusatz AS <aliasname> an. Neben seiner einfachen Form hat ein Join auch den Vorteil, daß nur eine Anweisung in der Datenbank ausgeführt wird. Allerdings hat ein Join den Nachteil, daß redundante Daten aus der äußeren Tabelle im Ergebnis erscheinen, wenn eine 1:N−Beziehung zwischen der äußeren und der inneren Tabelle besteht. Dies kann die Menge der von der Datenbank an die Anwendung übergebenen Daten drastisch erhöhen. Wenn Sie also einen Join verwenden, sollten Sie aus diesem Grund nur die Felder im View oder der Feldliste benutzen, die Sie wirklich benötigen. Die Performance eines Join hängt stark von der Performance des verwendeten Datenbank−Optimizer ab, besonders wenn der Join sich über mehr als zwei Tabellen erstreckt. Ein Beispiel für einen Join mit mehr als zwei Tabellen finden Sie in der Schlüsselwortdokumentation zu JOIN. Innere und äußere Joins arbeiten immer am Puffer vorbei. 4.24 Select mit LEFT OUTER JOIN (4.0) Geschachtelter Select SELECT * FROM VDBEKI WHERE BUKRS = '0020' AND RANL = '0002000500010'. SELECT * FROM VDBEPI WHERE BUKRS = '0020' AND = VDBEKI−RBELKPFD. RBELKPFD WRITE: / vdbeki−bukrs, vdbeki−rbelkpfd, vdbepi−dfaell. ENDSELECT. ENDSELECT. LEFT OUTER JOIN SELECT F1~BUKRS F1~RBELKPFD F2~DFAELL INTO (VDBEKI−BUKRS, VDBEKI−RBELKPFD, VDBEPI−DFAELL) FROM VDBEKI AS F1 LEFT OUTER JOIN VDBEPI AS F2 ON F1~BUKRS = F2~BUKRS 4.24 Select mit LEFT OUTER JOIN (4.0) 31 SAP_Tips AND F1~RBELKPFD = F2~RBELKPFD WHERE F1~BUKRS = '0020' AND F1~RANL = '0002000500010'. WRITE: / vdbeki−bukrs, vdbeki−rbelkpfd, vdbepi−dfaell. ENDSELECT. Bewertung Ein LEFT OUTER JOIN enthält wie ein innerer Join Kombinationen der Zeilen aus den Datenbanktabellen, deren Werte die in der ON <condition>−Klausel angegebene logische Bedingung erfüllen (Join−Bedingung). Die Zeilen der linken Tabelle, die die Bedingung nicht erfüllen, werden an das Ende der Ergebnismenge angehängt. D.h. die von der Datenbank erzeugte temporäre Tabelle enthält, im Gegensatz zu einem inneren Join, immer die gesamte linke Tabelle. Die Felder der rechten Tabelle für diese Zeilen werden auf Datenbankebene mit NULL−Werten gefüllt; ABAP kennt immer noch nur Initialwerte, nicht Nullen. Die normale WHERE−Bedingung wird dann auf die temporäre Tabelle angewendet. * Im Gegensatz zum INNER JOIN hängt das Ergebnis eines LEFT OUTER JOIN sehr wohl davon ab, ob die Bedingung in der ON− oder in der WHERE−Klausel angegeben wurde. Ohne WHERE−Klausel enthält die Ergebnistabelle immer alle Zeilen der linken Tabelle, während mit einer WHERE−Klausel Sätze aus der linken Tabelle herausgenommen werden können. * Die Anweisung LEFT OUTER JOIN enthält bestimmte Einschränkungen. Eine dieser Einschränkungen besteht darin, daß eine Selektion auf ein Feld der rechten Tabelle in einer AND−Bedingung angegeben werden muß. * In einem LEFT OUTER JOIN erscheinen Tabelleneinträge auch dann in der Join−Ergebnistabelle, wenn es keinen entsprechenden Datensatz in der rechten Tabelle gibt. In der Ergebnismenge ist dies also das Equivalent zu einer geschachtelten SELECT−Anweisung. * Innere und äußere Joins arbeiten immer am Puffer vorbei. * 4.24 Select mit LEFT OUTER JOIN (4.0) 32 5 Interne Tabellen 5.1 Interne Tabellen kopieren. Interne Tabellen kopieren DATA: TAB_SRC TYPE TAB1_100 WITH HEADER LINE, TAB_DEST TYPE TAB1_100 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 100 TIMES. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. Zu Fuß: Int. Tab. kopieren Table TAB_SRC hat 100 Sätze mit jeweils 10 Bytes. REFRESH TAB_DEST. LOOP AT TAB_SRC INTO TAB_DEST. APPEND TAB_DEST. ENDLOOP. DATA: TAB_SRC TYPE TAB1_100 WITH HEADER LINE, TAB_DEST TYPE TAB1_100 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 100 TIMES. APPEND TAB_SRC. 5 Interne Tabellen 33 SAP_Tips ENDDO. FLAG = 'X'. ENDIF. Lassen wir den Kernel arbeiten... Table TAB_SRC hat 100 Sätze mit jeweils 10 Bytes. TAB_DEST[] = TAB_SRC[]. Bewertung Int. Tab. kann mit MOVE wie jedes andere Datenobjekt kopiert werden. Wenn eine int. Tab eine Kopfzeile hat kann die Tabelle mit itab[] angesprochen werden. 5.2 Interne Tabellen vergleichen Interne Tabellen vergleichen DATA: TAB1 TYPE TAB1_100 WITH HEADER LINE, TAB2 TYPE TAB1_100 WITH HEADER LINE, L1 TYPE I, L2 TYPE I, TAB_DIFFERENT, FLAG. IF FLAG = SPACE. DO 100 TIMES. APPEND: TAB1, TAB2. ENDDO. FLAG = 'X'. ENDIF. Zu Fuß: Int. Tab. vergleichen. Tabelle TAB1 und TAB2 sind jeweils mit 100 Sätzen (Satzlänge 100 Bytes gefüllt. DESCRIBE TABLE: TAB1 LINES L1, 5.2 Interne Tabellen vergleichen 34 SAP_Tips TAB2 LINES L2. IF L1 <> L2. TAB_DIFFERENT = 'X'. ELSE. TAB_DIFFERENT = SPACE. LOOP AT TAB1. READ TABLE TAB2 INDEX SY−TABIX. IF TAB1 <> TAB2. TAB_DIFFERENT = 'X'. EXIT. ENDIF. ENDLOOP. ENDIF. IF TAB_DIFFERENT = SPACE. " ... ENDIF. DATA: TAB1 TYPE TAB1_100 WITH HEADER LINE, TAB2 TYPE TAB1_100 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 100 TIMES. APPEND: TAB1, TAB2. ENDDO. FLAG = 'X'. ENDIF. Lassen wir den Kernel arbeiten... Tabelle TAB1 und TAB2 sind jeweils mit 100 Sätzen (Satzlänge 100 Bytes gefüllt. IF TAB1[] = TAB2[]. " ... 5.2 Interne Tabellen vergleichen 35 SAP_Tips ENDIF. Bewertung Int. Tab. können wie andere Datenobjekte logisch verglichen werden. Zwei int. Tab. sind gleich wenn − dieselbe Zeilenanzahl vorhanden und − jedes Zeilenpaar gleich ist. Wenn eine int. Tab. eine Kopfzeile hat, kann die Tabelle mit itab[] angesprochen werden. Löschen doppelter Sätze Löschen doppelter Sätze einer internen Tabelle DATA: TAB_SRC TYPE TAB1_1000 WITH HEADER LINE, TAB_DEST TYPE TAB1_1000 WITH HEADER LINE, PREV_LINE LIKE LINE OF TAB_DEST, FLAG. IF FLAG = SPACE. DO 500 TIMES. TAB_SRC−K = SY−INDEX. APPEND TAB_SRC. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. Zu Fuß: Löschen doppelter Sätze. Tabelle TAB_DEST hat 1000 Sätze mit jeweils 100 Bytes und beinhaltet 500 doppelte Sätze. READ TABLE TAB_DEST INDEX 1 INTO PREV_LINE. LOOP AT TAB_DEST FROM 2. IF TAB_DEST = PREV_LINE. 5.2 Interne Tabellen vergleichen 36 SAP_Tips DELETE TAB_DEST. ELSE. PREV_LINE = TAB_DEST. ENDIF. ENDLOOP. Notwendiger Vorlauf für Beispiel DATA: TAB_SRC TYPE TAB1_1000 WITH HEADER LINE, TAB_DEST TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 500 TIMES. TAB_SRC−K = SY−INDEX. APPEND TAB_SRC. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. Lassen wir den Kernel arbeiten... Tabelle TAB_DEST hat 1000 Sätze mit jeweils 100 Bytes und beinhaltet 500 doppelte Sätze. DELETE ADJACENT DUPLICATES FROM TAB_DEST COMPARING K. Bewertung Mit der neuen DELETE Variante DELETE ADJACENT DUPLICATES Der Prozeß des Löschens doppelter Sätze kann dem Kernel überlassen werden. 5.2 Interne Tabellen vergleichen 37 SAP_Tips 5.3 Anhängen an eine Tabelle Anhängen einer int. tab. an eine andere DATA: TAB_SRC TYPE TAB1_100 WITH HEADER LINE, TAB_DEST TYPE TAB1_100 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 500 TIMES. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. Tabelle TAB_SRC und TAB_DEST sind beide mit 500 Einträgen gefüllt; jede mit 100 Bytes. TAB_SRC wird Zeile für Zeile an TAB_DEST angehängt LOOP AT TAB_SRC. APPEND TAB_SRC TO TAB_DEST. ENDLOOP. Notwendiger Vorlauf für Beispiel DATA: TAB_SRC TYPE TAB1_100 WITH HEADER LINE, TAB_DEST TYPE TAB1_100 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 500 TIMES. APPEND TAB_SRC. ENDDO. FLAG = 'X'. 5.3 Anhängen an eine Tabelle 38 SAP_Tips ENDIF. TAB_DEST[] = TAB_SRC[]. Lassen wir den Kernel arbeiten... Tabelle TAB_SRC und TAB_DEST sind beide mit 500 Einträgen gefüllt; jede mit 100 Bytes. TAB_SRC wird in einem Step an TAB_DEST gehängt. APPEND LINES OF TAB_SRC TO TAB_DEST. Bewertung Mit der neuen APPEND Variante: APPEND LINES OF itab1 TO itab2. Der Prozeß des Anhängens an eine andere Tabelle kann dem Kernel überlassen werden. 5.4 Aufbau von Tabellen ohne Dupletten Aufbau sort. Tab.: READ/INSERT vs. APPEND/SORT/DELETE DATA: TAB_SRC TYPE TAB1_1000 WITH HEADER LINE, TAB_DEST TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. TAB_SRC−K(15) = SY−ABCDE. SHIFT TAB_SRC−K(15) CIRCULAR LEFT BY 6 PLACES. DO 500 TIMES. TAB_SRC−K+15(5) = SY−INDEX. APPEND TAB_SRC. APPEND TAB_SRC. SHIFT TAB_SRC−K(15) CIRCULAR LEFT. ENDDO. FLAG = 'X'. ENDIF. Ein Step Zugriff 5.4 Aufbau von Tabellen ohne Dupletten 39 SAP_Tips Tabelle TAB_SRC ist mit 1.000 Sätzen gefüllt von denen 500 versch. Keys haben. REFRESH TAB_DEST. LOOP AT TAB_SRC. READ TABLE TAB_DEST WITH KEY K = TAB_SRC−K BINARY SEARCH. IF SY−SUBRC <> 0. INSERT TAB_SRC INTO TAB_DEST INDEX SY−TABIX. ENDIF. ENDLOOP. Notwendiger Vorlauf für Beispiel DATA: TAB_SRC TYPE TAB1_1000 WITH HEADER LINE, TAB_DEST TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. TAB_SRC−K(15) = SY−ABCDE. SHIFT TAB_SRC−K(15) CIRCULAR LEFT BY 6 PLACES. DO 500 TIMES. TAB_SRC−K+15(5) = SY−INDEX. APPEND TAB_SRC. APPEND TAB_SRC. SHIFT TAB_SRC−K(15) CIRCULAR LEFT. ENDDO. FLAG = 'X'. ENDIF. Drei Steps: copy, sort, delete Dupletten Tabelle TAB_SRC ist mit 1.000 Sätzen gefüllt von denen 500 versch. Keys haben. REFRESH TAB_DEST. 5.4 Aufbau von Tabellen ohne Dupletten 40 SAP_Tips LOOP AT TAB_SRC. APPEND TAB_SRC TO TAB_DEST. ENDLOOP. SORT TAB_DEST BY K. DELETE ADJACENT DUPLICATES FROM TAB_DEST COMPARING K. Bewertung Wenn die Datenmenge klein ist (< 20 Sätze) oder Lesezugriffe während des Füllens der Tabelle notwendig sind, dann ist der linke Zugriff mit READ/INSERT die richtige Wahl. Wenn jedoch das Datenvolumen größer ist und Lesezugriffe auf die komplett gefüllte Tabelle notwendig sind, dann ist der 'Drei Steps' Algorithmus zu bevorzugen. 5.5 Aufbau sortierter Tabellen Aufbau einer sort. int. Tabelle: READ/INSERT vs. APPEND/SORT Ein Step: READ/INSERT DATA: TAB_SRC TYPE TAB1_1000 WITH HEADER LINE, TAB_DEST TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. TAB_SRC−K = SY−ABCDE. DO 1000 TIMES. APPEND TAB_SRC. SHIFT TAB_SRC−K CIRCULAR. ENDDO. FLAG = 'X'. ENDIF TAB_DEST enthält 1000 Einträge REFRESH TAB_DEST. LOOP AT TAB_SRC. 5.5 Aufbau sortierter Tabellen 41 SAP_Tips READ TABLE TAB_DEST WITH KEY K = TAB_SRC−K BINARY SEARCH. INSERT TAB_SRC INTO TAB_DEST INDEX SY−TABIX. ENDLOOP. Zwei Steps: APPEND, dann SORT DATA: TAB_SRC TYPE TAB1_1000 WITH HEADER LINE, TAB_DEST TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. TAB_SRC−K = SY−ABCDE. DO 1000 TIMES. APPEND TAB_SRC. SHIFT TAB_SRC−K CIRCULAR. ENDDO. FLAG = 'X'. ENDIF. *TAB_DEST is filled with 1000 entries REFRESH TAB_DEST. LOOP AT TAB_SRC. APPEND TAB_SRC TO TAB_DEST. ENDLOOP. SORT TAB_DEST BY K. Bewertung Wenn die Datenmenge klein ist (< 20 Sätze) oder Lesezugriffe während des Füllens der Tabelle notwendig sind, dann ist der linke Zugriff mit READ/INSERT die richtige Wahl. Wenn jedoch das Datenvolumen größer ist und Lesezugriffe auf die komplett gefüllte Tabelle notwendig sind, dann ist der 'Zwei Steps' Algorithmus zu bevorzugen. 5.5 Aufbau sortierter Tabellen 42 SAP_Tips 5.6 Aufbau von summierten Tabellen Aufbau einer summ. und sort. Tabelle: READ/INSERT vs. COLLECT/SORT COLLECT Umschreibung mit READ BINARY DATA: TAB_SRC TYPE TAB3_10000 WITH HEADER LINE, TAB_DEST TYPE TAB3_10000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 2 TIMES. TAB_SRC−K(10) = SY−ABCDE. DO 5000 TIMES. SHIFT TAB_SRC−K(10) LEFT CIRCULAR. TAB_SRC−K+10(10) = SY−INDEX. APPEND TAB_SRC. ENDDO. ENDDO. FLAG = 'X'. ENDIF. FREE TAB_DEST. *Tabelle TAB_SRC ist mit 10.000 Sätzen gefüllt von denen 5.000 versch. Keys haben. LOOP AT TAB_SRC. READ TABLE TAB_DEST WITH KEY K = TAB_SRC−K BINARY SEARCH. IF SY−SUBRC = 0. ADD: TAB_SRC−VAL1 TO TAB_DEST−VAL1, TAB_SRC−VAL2 TO TAB_DEST−VAL2. MODIFY TAB_DEST INDEX SY−TABIX. 5.6 Aufbau von summierten Tabellen 43 SAP_Tips ELSE. INSERT TAB_SRC INTO TAB_DEST INDEX SY−TABIX. ENDIF. ENDLOOP. Sammeln mit COLLECT DATA: TAB_SRC TYPE TAB3_10000 WITH HEADER LINE, TAB_DEST TYPE TAB3_10000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 2 TIMES. TAB_SRC−K(10) = SY−ABCDE. DO 5000 TIMES. SHIFT TAB_SRC−K(10) LEFT CIRCULAR. TAB_SRC−K+10(10) = SY−INDEX. APPEND TAB_SRC. ENDDO. ENDDO. FLAG = 'X'. ENDIF. FREE TAB_DEST. *Tabelle TAB_SRC ist with 10.000 Sätzen gefüllt, von denen 5.000 verschiedene Keys haben. LOOP AT TAB_SRC. COLLECT TAB_SRC INTO TAB_DEST. ENDLOOP. SORT TAB_DEST BY K. Bewertung 5.6 Aufbau von summierten Tabellen 44 SAP_Tips Wenn man eine summierende Funktion benötigt, dann COLLECT verwenden ! READ BINARY läuft in O( log2( n ) ) Zeit, und der Index der int. Tabelle muß bei jedem INSERT neu justiert werden. COLLECT jedoch benutzt einen Hash−Algorithmus und ist deshalb unabhämgig von der Anzahl der Einträge ( z.B. O( 1 )) und braucht daher keinen Tabellen−Index. Wenn man den letzten Sort benutzt wird die interne Tabelle erst nach dem COLLECT sortiert. * Für kleine Datenmengen ist der READ/INSERT Zugriff nicht schlecht, aber bei größeren Datenmengen (> 1000) ist der COLLECT viel schneller. .Achtung: Beim Füllen einer int.Tab. sollte COLLECT nicht in Kombination mit anderen füllenden Befehlen (APPEND, INSERT, MODIFY SELECT * INTO TABLE und/oder SELECT * APPENDING TABLE) verwendet werden. Wenn man COLLECT mit den anderen Befehlen mischt kann der Hash−Algorithmus nicht verwendet werden. In diesem Fall wird eine normale lineare Suche durchgeführt, die dramatisch langsamer ist: O ( n ). 5.7 Lineare Suche oder binary search Lineare Suche oder binary search Lineare Suche einer internen Tabelle DATA: TAB TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 1000 TIMES. APPEND TAB. ENDDO. FLAG = 'X'. ENDIF. *Table TAB ist gefüllt mit 1000 Sätzen von je 100 Byte. Der READ endet mit SY−SUBRC=4 READ TABLE TAB WITH KEY K = 'X'. Binary search einer int. Tab. DATA: TAB TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 1000 TIMES. APPEND TAB. 5.7 Lineare Suche oder binary search 45 SAP_Tips ENDDO. FLAG = 'X'. ENDIF. *Table TAB ist gefüllt mit 1000 Sätzen von je 100 Byte. Der READ endet mit SY−SUBRC=4 READ TABLE TAB WITH KEY K = 'X' BINARY SEARCH. Bewertung Wenn int.Tab. viele Einträge (>20) haben, ist eine lineare Suche durch alle Einträge sehr zeit−intensiv. Versuchen die Tabelle sortiert zu halten and binary search benutzen. Wenn eine Tab. n Sätze hat, dann braucht eine lineare Suche O( n ) Zeit während binary search nur O( log2( n ) ) Zeit benötigt. 5.8 Versch. Arten von Schlüsselzugriffen Schlüsselzugriff: Implizite gegen explizite Keyfeld−Spezifikation Zugriff über impliziten default Key DATA: TAB TYPE TAB2_100 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 30 TIMES. APPEND TAB. ENDDO. FLAG = 'X'. ENDIF. *TAB ist mit 30 Einträgen mit jeweils 500 Bytes gefüllt. Der READ endet mit SY−SUBRC=4 MOVE SPACE TO TAB. TAB−K = 'X'. READ TABLE TAB BINARY SEARCH. Zugriff über expliziten Key. DATA: TAB TYPE TAB2_100 WITH HEADER LINE, 5.8 Versch. Arten von Schlüsselzugriffen 46 SAP_Tips FLAG. IF FLAG = SPACE. DO 30 TIMES. APPEND TAB. ENDDO. FLAG = 'X'. ENDIF. *TAB ist mit 30 Einträgen mit jeweils 500 Bytes gefüllt. Der READ endet mit SY−SUBRC=4 READ TABLE TAB WITH KEY K = 'X' BINARY SEARCH. Bewertung Wenn möglich sollten die Keyfelder für den expliziten Zugriff gefüllt sein. Andernfalls müssen sie dynamisch vom Run−Time−System errechnet werden. 5.9 Zweite Index−Tabelle Anlegen einer Sek−Index Tabelle um linearen Zugriff zu vermeiden. Keine Sek−Index Tab. => Lineare Suche DATA: TAB TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. TAB−DATE = SY−DATUM + 500. DO 1000 TIMES. APPEND TAB. SUBTRACT 1 FROM TAB−DATE. ENDDO. FLAG = 'X'. ENDIF. *Tab. TAB ist mit 1000 Einträgen gefüllt. Der READ findet den 500. Eintrag. 5.9 Zweite Index−Tabelle 47 SAP_Tips READ TABLE TAB WITH KEY DATE = SY−DATUM. IF SY−SUBRC = 0. " ... ENDIF. Binary search mit Sek−Index Tab. DATA: TAB TYPE TAB1_1000 WITH HEADER LINE, TAB_INDEX TYPE TAB_INDEX WITH HEADER LINE, DATE TYPE D, FLAG. IF FLAG = SPACE. DATE = SY−DATUM + 500. DO 1000 TIMES. TAB_INDEX−DATE = TAB−DATE = DATE. APPEND TAB. TAB_INDEX−INDX = SY−TABIX. APPEND TAB_INDEX. SUBTRACT 1 FROM DATE. ENDDO. SORT TAB_INDEX BY DATE. FLAG = 'X'. ENDIF. *Tab. TAB ist mit 1000 Einträgen gefüllt. Der READ findet den 500. Eintrag. READ TABLE TAB_INDEX WITH KEY DATE = SY−DATUM BINARY SEARCH. IF SY−SUBRC = 0. READ TABLE TAB INDEX TAB_INDEX−INDX. " ... 5.9 Zweite Index−Tabelle 48 SAP_Tips ENDIF. Bewertung Benötigt man wiederholt Zugriffe auf eine int. Tab. mit versch. Keys, ist es zu empfehlen eigene Sek.−Tabellen aufzubauen. Mit einer Sek.−Tab. kann man eine lineare Suche mit einem BINNARY SEARCH plus einem Index Zugriff ersetzen. 5.10 Key Zugriffe auf mehrere Zeilen Key Zugriffe auf mehrere Zeilen. LOOP/CHECK gegen LOOP. Key Zugriff mit LOOP/CHECK DATA: TAB TYPE TAB2_100 WITH HEADER LINE, FLAG. CONSTANTS: KVAL TYPE LINE2−K VALUE 'X'. IF FLAG = SPACE. TAB−K = SPACE. DO 95 TIMES. APPEND TAB. ENDDO. TAB−K = KVAL. DO 5 TIMES. APPEND TAB. ENDDO. FLAG = 'X'. ENDIF. *Tabelle TAB hat 100 Sätze mit jeweils 500 Bytes. 5 Einträge erfüllen die Schlüsselbedingung LOOP AT TAB. CHECK TAB−K = KVAL. " ... 5.10 Key Zugriffe auf mehrere Zeilen 49 SAP_Tips ENDLOOP. Key Zugriff mit LOOP ... WHERE DATA: TAB TYPE TAB2_100 WITH HEADER LINE, FLAG. CONSTANTS: KVAL TYPE LINE2−K VALUE 'X'. IF FLAG = SPACE. TAB−K = SPACE. DO 95 TIMES. APPEND TAB. ENDDO. TAB−K = KVAL. DO 5 TIMES. APPEND TAB. ENDDO. FLAG = 'X'. ENDIF. *Tabelle TAB hat 100 Sätze mit jeweils 500 Bytes. 5 Einträge erfüllen die Schlüsselbedingung LOOP AT TAB WHERE K = KVAL. " ... ENDLOOP. Bewertung LOOP ... WHERE ist schneller als LOOP/CHECK, denn LOOP ... WHERE ermittelt die spezifizierte Bedingung intern. Wie mit jedem logischem Ausdruck ist die Performance besser, wenn die Operanden des Vergleichs vom gleichen Typ sind. Die Performance kann gesteigert werden, wenn LOOP ... WHERE mit FROM i1 und/oder TO i2 −wenn möglich− verwendet wird. 5.10 Key Zugriffe auf mehrere Zeilen 50 SAP_Tips 5.11 Explizite Arbeitsbereiche Explizite Arbeitsbereiche anstatt gefüllter Kopfzeilen. *># 50 Tabellen Operationen mit Kopfzeile DATA: TAB TYPE TAB2_100 WITH HEADER LINE, TAB_WA LIKE LINE OF TAB. REFRESH TAB. *Die Zeilenlänge von Tab. TAB ist 500 Bbytes. TAB = TAB_WA. APPEND TAB. Tab−Operationen mit expl. Arbeitsber. DATA: TAB TYPE TAB2_100 WITH HEADER LINE, TAB_WA LIKE LINE OF TAB. REFRESH TAB. *Die Zeilenlänge von Tab. TAB ist 500 Bbytes. APPEND TAB_WA TO TAB. Bewertung Vermeidung von unnötigen MOVEs in Arbeitsbereichen. APPEND wa TO tab. INSERT wa INTO tab. COLLECT wa INTO tab. MODIFY tab FROM wa. READ TABLE LOOP AT tab INTO wa. tab INTO wa. where zusätzlich... 5.11 Explizite Arbeitsbereiche 51 SAP_Tips 5.12 Interne Tabellen sortieren interne Tabellen sortieren Sortieren mit default Sortierschlüssel. DATA: TAB TYPE TAB2_100 WITH HEADER LINE. REFRESH TAB. DO 100 TIMES. TAB−K = 100 − SY−INDEX. APPEND TAB. ENDDO. *Tabelle TAB hat 100 Sätze mit jeweils 500 Bytes. SORT TAB. Sortieren mit expl. Sortierschlüssel DATA: TAB TYPE TAB2_100 WITH HEADER LINE. REFRESH TAB. DO 100 TIMES. TAB−K = 100 − SY−INDEX. APPEND TAB. ENDDO. Tabelle TAB hat 100 Sätze mit jeweils 500 Bytes. SORT TAB BY K. Bewertung Je genauer der Sortierschlüssel angegeben wird desto schneller läuft das Programm. 5.13 Interne Tabellen miteinander verknüpfen. Zwei sortierte int. Tab. mit gleichen Keys. Join: loop tab1, read tab2 5.12 Interne Tabellen sortieren 52 SAP_Tips DATA: TAB1 TYPE TAB1_1000 WITH HEADER LINE, TAB2 TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 1000 TIMES. TAB1−K = SY−INDEX. APPEND TAB1. ENDDO. DO 300 TIMES. TAB2−K = SY−INDEX * 2. APPEND TAB2. ENDDO. FLAG = 'X'. ENDIF. *Tab. TAB1 mit 1000 Sätzen jeweils 100 Bytes. Tab. TAB2 mit 300 Sätzen jeweils 100 Bytes. *Tab. TAB2 ist absteigend sortiert nach K. LOOP AT TAB1. READ TABLE TAB2 WITH KEY K = TAB1−K BINARY SEARCH. IF SY−SUBRC = 0. " ... ENDIF. ENDLOOP. Besser: Parallele Cursor DATA: TAB1 TYPE TAB1_1000 WITH HEADER LINE, TAB2 TYPE TAB1_1000 WITH HEADER LINE, I2 TYPE I, FLAG. IF FLAG = SPACE. DO 1000 TIMES. TAB1−K = SY−INDEX. APPEND TAB1. ENDDO. DO 300 TIMES. TAB2−K = SY−INDEX * 2. APPEND TAB2. ENDDO. FLAG = 'X'. ENDIF. 5.12 Interne Tabellen sortieren 53 SAP_Tips *Tab. TAB1 mit 1000 Sätzen jeweils 100 Bytes. Tab. TAB2 mit 300 Sätzen jeweils 100 Bytes. *Tab. TAB2 ist absteigend sortiert nach K. I2 = 1. LOOP AT TAB1. READ TABLE TAB2 INDEX I2. IF SY−SUBRC <> 0. EXIT. ENDIF. IF TAB2−K = TAB1−K. " ... ADD 1 TO I2. ENDIF. ENDLOOP. Bewertung Wenn TAB1 n1 und TAB2 n2 Einträge hätte, dann ist der Algorithmus O( n1 * log2( n2 ) ) um beide zu verknüpfen; dagegen braucht der parallele Cursor Zugriff O( n1 + n2 ) Zeit. Der obige parallele Cursor Zugriff setzt voraus, daß die TAB2 Einträge zu den TAB1 Einträgen 1 zu 1 zugeordnet sind. Falls die Anforderung anders ist, wird die Ausprogrammierung der parallelen Cursor komplizierter, jedoch wird die Performance−Charakteristik die gleiche sein. 5.14 Geschachtelte LOOPs Geschachtelte LOOPs und sortierte Tabellen. Geschachtelte LOOPs DATA: TAB1 TYPE TAB1_100 WITH HEADER LINE, TAB2 TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 100 TIMES. TAB1−K = TAB2−K = SY−INDEX. APPEND TAB1. 5.14 Geschachtelte LOOPs 54 SAP_Tips DO 10 TIMES. APPEND TAB2. ENDDO. ENDDO. FLAG = 'X'. ENDIF. Tabelle TAB1 hat 100 Sätze mit jeweils 100 Bytes. Tabelle TAB2 hat 10 * 100 = 1000 Sätze mit jeweils 100 Bytes. LOOP AT TAB1. LOOP AT TAB2 WHERE K = TAB1−K. " ... ENDLOOP. ENDLOOP. Besser: Parallele Cursors DATA: TAB1 TYPE TAB1_100 WITH HEADER LINE, TAB2 TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 100 TIMES. TAB1−K = TAB2−K = SY−INDEX. APPEND TAB1. DO 10 TIMES. APPEND TAB2. ENDDO. ENDDO. FLAG = 'X'. 5.14 Geschachtelte LOOPs 55 SAP_Tips ENDIF. DATA: TAB1 TYPE TAB1_100 WITH HEADER LINE, TAB2 TYPE TAB1_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 100 TIMES. TAB1−K = TAB2−K = SY−INDEX. APPEND TAB1. DO 10 TIMES. APPEND TAB2. ENDDO. ENDDO. FLAG = 'X'. ENDIF. *Tabelle TAB1 hat 100 Sätze mit jeweils 100 Bytes. Tabelle TAB2 hat 10 * 100 = 1000 Sätze mit jeweils 100 Bytes. Tabelle TAB1 und TAB2 sind absteigend *nach K sortiert. I2 = 1. LOOP AT TAB1. LOOP AT TAB2 FROM I2. IF TAB2−K <> TAB1−K. I2 = SY−TABIX. EXIT. ENDIF. " ... ENDLOOP. ENDLOOP. 5.14 Geschachtelte LOOPs 56 SAP_Tips Bewertung Wenn TAB1 n1 und TAB2 n2 Einträge hätte, dann ist der Algorithmus O( n1 * log2( n2 ) ) um beide zu verknüpfen; dagegen braucht der parallele Cursor Zugriff O( n1 + n2 ) Zeit. Der obige parallele Cursor Zugriff setzt voraus, daß die TAB2 Einträge zu den TAB1 Einträgen 1 zu 1 zugeordnet sind. Falls die Anforderung anders ist, wird die Ausprogrammierung der parallelen Cursor komplizierter, jedoch wird die Performance−Charakteristik die gleiche sein. 5.15 Modifizieren einzelner Komponenten Modifizieren einzelner Komponenten einer int. Tab. Modifizieren aller Komponenten (Felder). DATA: TAB TYPE TAB2_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 500 TIMES. APPEND INITIAL LINE TO TAB. ENDDO. FLAG = 'X'. ENDIF. *Tabelle TAB hat 500 Einträge mit jeweils 500 Bytes. Hier würden nur 8 Byte modifiziert werden, obwohl die gesamte Leiste weggeschrieben wird. TAB−DATE = SY−DATUM. DO 500 TIMES. MODIFY TAB INDEX SY−INDEX. ENDDO. Nur ausgewählte Komponenten modifizieren. DATA: TAB TYPE TAB2_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 500 TIMES. 5.15 Modifizieren einzelner Komponenten 57 SAP_Tips APPEND INITIAL LINE TO TAB. ENDDO. FLAG = 'X'. ENDIF. *Tabelle TAB hat 500 Einträge mit jeweils 500 Bytes. Hier werden tatsächlich nur die 8 Byte des Feldes DATE weggeschrieben. TAB−DATE = SY−DATUM. DO 500 TIMES. MODIFY TAB INDEX SY−INDEX TRANSPORTING DATE. ENDDO. Bewertung Mit der MODIFY Variante: MODIFY itab ... TRANSPORTING f1 f2 ... Die Zeit zum Updaten der int. Zeile kann beschleunigt werden. Je länger die Zeile desto langsamer ist die Update Zeit. Der Effekt wächst mit der Komplexität der Typstruktur einer int. Tab. 5.16 Modifizieren mehrerer Zeilen Modifizieren einzelner Komponenten mehrerer Zeilen Modifzieren aller Komponenten. DATA: TAB TYPE TAB4_100 WITH HEADER LINE. REFRESH TAB. DO 20 TIMES. APPEND SY−INDEX TO TAB−INTTAB. ENDDO. DO 100 TIMES. APPEND TAB. ENDDO. *Tabelle TAB hat 100 Einträge. Eine Zeile hat 2 Komponenten, FLAG type C und eine Tabelle INTTAB mit 5.16 Modifizieren mehrerer Zeilen 58 SAP_Tips jeweils 20 Einträgen. Flag soll für alle 100 Zeilen *angeschaltet werden. LOOP AT TAB. IF TAB−FLAG IS INITIAL. TAB−FLAG = 'X'. ENDIF. MODIFY TAB. ENDLOOP. Modifizieren nur ausgewählter Komponenten DATA: TAB TYPE TAB4_100 WITH HEADER LINE, WA LIKE LINE OF TAB. REFRESH TAB. DO 20 TIMES. APPEND SY−INDEX TO TAB−INTTAB. ENDDO. DO 100 TIMES. APPEND TAB. ENDDO. *Tabelle TAB hat 100 Einträge. Eine Zeile hat 2 Komponenten, FLAG type C und eine Tabelle INTTAB mit jeweils 20 Einträgen. Flag soll für alle 100 Zeilen *angeschaltet werden. TAB−FLAG = 'X'. MODIFY TAB TRANSPORTING FLAG WHERE FLAG IS INITIAL. Bewertung Mit der MODIFY Variante: MODIFY itab ... TRANSPORTING f1 f2 ... WHERE cond. Die Zeit zum Updaten der int. Zeile kann beschleunigt werden. Besonders wenn Tabellen in einer Zeile mit eingebunden sind, können diese beim Update ignoriert werden; der Performance−Gewinn ist besonders gut. 5.16 Modifizieren mehrerer Zeilen 59 SAP_Tips 5.17 Einfügen einer int. Tab. Einfügen einer int. Tab. in eine andere int. Tab. Zu Fuß: Einfügen einer Tabelle. DATA: TAB_SRC TYPE TAB1_100 WITH HEADER LINE, TAB_DEST TYPE TAB1_100 WITH HEADER LINE, IDX TYPE I, FLAG. IF FLAG = SPACE. DO 500 TIMES. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. *Tabelle TAB_SRC und TAB_DEST sind beide mit 500 Sätzen gefüllt; jeweils 10 Bytes. TAB_SRC wird in TAB_DEST eingefügt Zeile für Zeile mit dem Index IDX. IDX = 250. LOOP AT TAB_SRC. INSERT TAB_SRC INTO TAB_DEST INDEX IDX. ADD 1 TO IDX. ENDLOOP. assen wir den Kernel arbeiten... DATA: TAB_SRC TYPE TAB1_100 WITH HEADER LINE, TAB_DEST TYPE TAB1_100 WITH HEADER LINE, IDX TYPE I, FLAG. 5.17 Einfügen einer int. Tab. 60 SAP_Tips IF FLAG = SPACE. DO 500 TIMES. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. *Tabelle TAB_SRC und TAB_DEST sind beide mit 500 Sätzen gefüllt; jeweils 10 Bytes. TAB_SRC wird in TAB_DEST mit einem Step eingefügt mit dem Index IDX (250). IDX = 250. INSERT LINES OF TAB_SRC INTO TAB_DEST INDEX IDX. Bewertung Mit der neuen INSERT Variante: INSERT LINES OF itab1 INTO itab2 INDEX idx. Der Prozeß des Anhängens an eine andere Tabelle kann dem Kernel überlassen werden. 5.18 Löschen mehrerer Zeilen Löschen mehrerer Zeilen Zu Fuß: Löschen mehrerer Zeilen. DATA: TAB_SRC TYPE TAB2_1000 WITH HEADER LINE, TAB_DEST TYPE TAB2_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 1000 TIMES. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. 5.18 Löschen mehrerer Zeilen 61 SAP_Tips TAB_DEST[] = TAB_SRC[]. SORT TAB_DEST BY K. " Force an index to be allocated Tabelle TAB_DEST hat 1000 Sätze mit jeweils 500 Bytes und Zeilen; 450 bis 550 sollen gelöscht werden. DO 101 TIMES. DELETE TAB_DEST INDEX 450. ENDDO. Lassen wir den Kernel arbeiten... DATA: TAB_SRC TYPE TAB2_1000 WITH HEADER LINE, TAB_DEST TYPE TAB2_1000 WITH HEADER LINE, FLAG. IF FLAG = SPACE. DO 1000 TIMES. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. SORT TAB_DEST BY K. " Force an index to be allocated Tabelle TAB_DEST hat 1000 Sätze mit jeweils 500 Bytes und Zeilen;450 bis 550 sollen gelöscht werden. DELETE TAB_DEST FROM 450 TO 550. Bewertung Mit der neuen DELETE Variante: DELETE itab FROM ... TO ... Der Prozeß des Löschens kann dem Kernel überlassen werden. 5.19 Löschen eines Sets von Zeilen. Löschen eines Sets von Zeilen spezifiziert in der WHERE Klausel. Zu Fuß: Löschen eines Sets von Zeilen 5.19 Löschen eines Sets von Zeilen. 62 SAP_Tips DATA: TAB_SRC TYPE TAB2_1000 WITH HEADER LINE, TAB_DEST TYPE TAB2_1000 WITH HEADER LINE, KVAL LIKE TAB_DEST−K VALUE 'berta', FLAG. IF FLAG = SPACE. DO 250 TIMES. TAB_SRC−K = 'anton'. APPEND TAB_SRC. TAB_SRC−K = 'berta'. APPEND TAB_SRC. TAB_SRC−K = 'carl '. APPEND TAB_SRC. TAB_SRC−K = 'drago'. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. *Tabelle TAB_DEST hat 1000 Sätze mit jeweils 500 Bytes, 250 entsprechen der WHERE Klausel. LOOP AT TAB_DEST WHERE K = KVAL. DELETE TAB_DEST. ENDLOOP. Lassen wir den Kernel arbeiten... DATA: TAB_SRC TYPE TAB2_1000 WITH HEADER LINE, TAB_DEST TYPE TAB2_1000 WITH HEADER LINE, KVAL LIKE TAB_DEST−K VALUE 'berta', FLAG. IF FLAG = SPACE. DO 250 TIMES. TAB_SRC−K = 'anton'. APPEND TAB_SRC. 5.19 Löschen eines Sets von Zeilen. 63 SAP_Tips TAB_SRC−K = 'berta'. APPEND TAB_SRC. TAB_SRC−K = 'carl '. APPEND TAB_SRC. TAB_SRC−K = 'drago'. APPEND TAB_SRC. ENDDO. FLAG = 'X'. ENDIF. TAB_DEST[] = TAB_SRC[]. Tabelle TAB_DEST hat 1000 Sätze mit jeweils 500 Bytes, 250 entsprechen der WHERE Klausel. DELETE TAB_DEST WHERE K = KVAL. Bewertung Mit der neuen DELETE Variante: DELETE itab [FROM ...] [TO ...] WHERE ... Wenn möglich sollte WHERE mit FROM benutzt werden ... und/oder TO um mehr Performance zu bekommen. Die Performance steigt mit DELETE itab WHERE ... anstatt LOOP AT itab WHERE ... DELETE itab. ENDLOOP. mit der Anzahl der Einträge in der int. Tab. *−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 5.20 Bestimmte Tabelleneinträge zählen Mit Feldtransport DATA: TAB1 LIKE VDARL OCCURS 0 WITH HEADER LINE. SELECT * FROM VDARL UP TO 200 ROWS INTO TABLE TAB1. CLEAR: COUNT. LOOP AT TAB1 WHERE SBEA = '07'. COUNT = COUNT + 1. ENDLOOP. Ohne Feldtransport DATA: TAB1 LIKE VDARL OCCURS 0 WITH HEADER LINE. 5.20 Bestimmte Tabelleneinträge zählen 64 SAP_Tips DATA: WA LIKE VDARL. SELECT * FROM VDARL UP TO 200 ROWS INTO TABLE TAB1. CLEAR: COUNT. LOOP AT TAB1 TRANSPORTING NO FIELDS WHERE SBEA = '07'. COUNT = COUNT + 1. ENDLOOP. Bewertung Int. Tab. enthält 200 Sätze mit der Satzlänge von VDARL. Falls die Tabelleninhalte nicht benötigt werden, kann zum Zählen verschiedener Bedingungen aus einer int. Tab. der Zusatz TRANSPORTING NO FIELDS den LOOP beschleunigen. *−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 5.21 Großen Datenbestand filtern Die schnelle Indexsuche nutzen... DATA: TAB1 LIKE VDARL OCCURS 0 WITH HEADER LINE. DATA: Z LIKE SY−TFILL. SELECT * FROM VDARL UP TO 800 ROWS INTO TABLE TAB1. SORT TAB1 BY SBEA. READ TABLE TAB1 WITH KEY SBEA = '07'. LOOP AT TAB1 FROM SY−TABIX. IF TAB1−SBEA NE '07'. EXIT. ENDIF. ENDLOOP. Mit klassischem LOOP DATA: TAB1 LIKE VDARL OCCURS 0 WITH HEADER LINE. 5.21 Großen Datenbestand filtern 65 SAP_Tips SELECT * FROM VDARL UP TO 800 ROWS INTO TABLE TAB1. SORT TAB1 BY SBEA. LOOP AT TAB1 WHERE SBEA = '07'. ENDLOOP. Bewertung Voraussetzungen: − Es soll nach einem 'Nicht−Key' Feld gesucht werden. − Die interne Tabelle ist sortiert nach SBEA − TAB1 enthält nur ausgewählte Felder nicht einen INCLUDE STRUCTURE. − Falls die Tabelle nicht sortiert gehalten werden kann ist die rechte Seite performanter. *−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 5.22 Geschachtelte Tab. oder EXTRACT Verbundene interne Tabellen IF Z1 = ' '. DATA: BEGIN OF KOPF OCCURS 0, NR1(5), DATEN1(10), DATEN2(10), END OF KOPF. DATA: BEGIN OF POSITIONEN OCCURS 0, NR1(5), NR2(5), DATEN1(10), DATEN2(10), END OF POSITIONEN. KOPF−NR1 = '0'. DO 100 TIMES. KOPF−NR1 = KOPF−NR1 + 1. POSITIONEN−NR1 = POSITIONEN−NR1 + 1. 5.22 Geschachtelte Tab. oder EXTRACT 66 SAP_Tips KOPF−DATEN1 = 'TEST'. APPEND KOPF. POSITIONEN−NR2 = '0'. DO 10 TIMES. POSITIONEN−NR2 = POSITIONEN−NR2 + 1. POSITIONEN−DATEN1 = 'TEST'. APPEND POSITIONEN. ENDDO. ENDDO. Z1 = '1'. ENDIF. LOOP AT KOPF. LOOP AT POSITIONEN WHERE NR1 = KOPF−NR1. ENDLOOP. ENDLOOP. Ein Extract Muß global def. sein *field−groups: header, kopf, positionen. *data: nr1(5), nr2(5), k_daten1(10), k_daten2(10), p_daten1(10), p_daten2(10). *insert nr1 into header. *insert k_daten1 k_daten2 into kopf. *insert nr2 p_daten1 p_daten2 into positionen. IF Z2 = ' '. NR1 = '0'. DO 100 TIMES. 5.22 Geschachtelte Tab. oder EXTRACT 67 SAP_Tips NR1 = NR1 + 1. K_DATEN1 = 'TEST'. EXTRACT KOPF. NR2 = '0'. DO 10 TIMES. NR2 = NR2 + 1. P_DATEN1 = 'TEST'. EXTRACT POSITIONEN. ENDDO. ENDDO. Z2 = '1'. ENDIF. *extract LOOP. ENDLOOP. Bewertung *Voraussetzungen: *− A C H T U N G: Dieses Bsp. kann nur 1x ausgeführt werden, da Field−Groups nur 1x pro Report definiert werden dürfen (sonst DUMP). Nur für Reports zu empfehlen nicht im Dialog verwenden. *− Der fachliche Hintergrund ist in beiden Bsp. gleich. Es sollen Kopfdaten mit den zugehörigen Positionsdaten bearbeitet werden. Beide Bsp. beinhalten die gleiche Datenmenge von 100 Kopfsätzen mit jeweils 10 Positionen. *− Noch extremer ist der Performancegewinn bei weiteren Schachtelungen. *−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 5.22 Geschachtelte Tab. oder EXTRACT 68 SAP_Tips 5.23 Anzahl Tabelleneinträge ermitteln Zu Fuß: Zählen... DATA: BEGIN OF ITAB OCCURS 0, TEXT(5), ZAHL1 TYPE P, ZAHL2 TYPE P, END OF ITAB. CLEAR COUNT. ITAB−TEXT = 'Test'. REFRESH ITAB. DO 1000 TIMES. APPEND ITAB. ENDDO. LOOP AT ITAB. COUNT = COUNT + 1. ENDLOOP. Lassen wir den Kernel arbeiten... DATA: BEGIN OF ITAB OCCURS 0, TEXT(5), ZAHL1 TYPE P, ZAHL2 TYPE P, END OF ITAB. ITAB−TEXT = 'Test'. REFRESH ITAB. DO 1000 TIMES. APPEND ITAB. ENDDO. DESCRIBE TABLE ITAB LINES SY−TFILL. Bewertung 5.23 Anzahl Tabelleneinträge ermitteln 69 SAP_Tips Die int. Tab. hat 1000 Einträge. Zum Auszählen von internen Tabellen (ohne Bedingung) ist describe Pflicht. 5.24 Tabelle vom Typ SORTED (4.0) Key−Zugriff auf Standard−ITAB DATA: ITAB LIKE VDARL OCCURS 0 WITH HEADER LINE.. SELECT * FROM VDARL INTO TABLE ITAB WHERE BUKRS = '0020' AND SARCHIV ='' AND RANL BETWEEN '0002000000010' AND '0002000600000'. READ TABLE ITAB WITH KEY MANDT = SY−MANDT BUKRS = '0020' SARCHIV = ' ' RANL = '0002000500010'. Key Zugriff auf SORTED−ITAB DATA: STAB LIKE SORTED TABLE OF VDARL WITH UNIQUE KEY MANDT BUKRS SARCHIV RANL WITH HEADER LINE. SELECT * FROM VDARL INTO TABLE STAB WHERE BUKRS = '0020' AND SARCHIV ='' AND RANL BETWEEN '0002000000010' AND '0002000600000'. READ TABLE STAB WITH TABLE KEY MANDT = SY−MANDT 5.24 Tabelle vom Typ SORTED (4.0) 70 SAP_Tips BUKRS = '0020' SARCHIV = ' ' RANL = '0002000500010'. Bewertung Es gibt drei unterschiedliche Typen von internen Tabellen: Standardtabelle, sortierte Tabelle und Hash−Tabelle. · In einer Standardtabelle greifen Sie auf Datensätze entweder über den Tabellenindex oder den Schlüssel zu. Wenn Sie den Schlüssel verwenden, steht die Antwortzeit in linearer Abhängigkeit zur Anzahl der Tabelleneinträge. Der Schlüssel einer Standardtabelle ist immer NON−UNIQUE. · In einer sortierten Tabelle werden die Einträge immer nach dem Schlüssel in absteigender Reihenfolge sortiert gespeichert. Sie können auf Datensätze entweder über den Tabellenindex oder über den Schlüssel zugreifen. Wenn Sie den Schlüssel verwenden, steht die Antwortzeit in logarithmischer Abhängigkeit zur Anzahl der Tabelleneinträge, da das System die binäre Suche verwendet. Der Schlüssel einer sortierten Tabelle kann entweder UNIQUE oder NON−UNIQUE sein. * Füllen Sie sortierte Tabellen nicht über Indexoperationen (INSERT wa INTO tab1 INDEX tabix, APPEND tab1 FROM wa), da dies die Sortierreihenfolge durcheinanderbringen kann. Eine sortierte Tabelle kann nicht neu sortiert werden. Der Versuch, eine sortierte Tabelle zu sortieren, führt zu einer Syntaxprüfung im ABAP Editor. *Schlüsselzugriff können Sie bei jedem Tabellentyp verwenden. Jedoch ist die Performance dieser Operationen für jeden Tabellentyp anders (O(n), O(log(n), O(1)). INSERT mit Index oder APPEND sind gefährlich in sortierten Tabellen, da sie leicht die Sortierreihenfolge durcheinanderbringen könen. Aus syntaktischen Gründen sind sie in Hash−Tabellen nicht zulässig. 5.25 Tabelle vom Typ HASHED (4.0) Key−Zugriff auf Standard−ITAB Key−Zugriff auf Standard−ITAB DATA: ITAB LIKE VDARL OCCURS 0 WITH HEADER LINE.. SELECT * FROM VDARL INTO TABLE ITAB WHERE BUKRS = '0020' AND SARCHIV ='' AND RANL BETWEEN '0002000000010' AND '0002000600000'. READ TABLE ITAB WITH KEY MANDT = SY−MANDT 5.25 Tabelle vom Typ HASHED (4.0) 71 SAP_Tips BUKRS = '0020' SARCHIV = ' ' RANL = '0002000500010'. Key Zugriff auf HASHED−ITAB DATA: HTAB LIKE HASHED TABLE OF VDARL WITH UNIQUE KEY MANDT BUKRS SARCHIV RANL WITH HEADER LINE. SELECT * FROM VDARL INTO TABLE HTAB WHERE BUKRS = '0020' AND SARCHIV ='' AND RANL BETWEEN '0002000000010' AND '0002000600000'. READ TABLE HTAB WITH TABLE KEY MANDT = SY−MANDT BUKRS = '0020' SARCHIV = ' ' RANL = '0002000500010'. Bewertung Es gibt drei unterschiedliche Typen von internen Tabellen: Standardtabelle, sortierteTabelle und Hash−Tabelle. · In einer Standardtabelle greifen Sie auf Datensätze entweder über den Tabellenindex oder den Schlüssel zu. Wenn Sie den Schlüssel verwenden, steht die Antwortzeit in linearer Abhängigkeit zur Anzahl der Tabelleneinträge. Der Schlüssel einer Standardtabelle ist immer NON−UNIQUE. · Auf Hash−Tabellen können Sie NUR über ihren Schlüssel zugreifen. Die Antwortzeit ist konstant und hängt NICHT von der Anzahl der Tabelleneinträge ab, da das System einen Hash−Algorithmus verwendet, um auf Einträge zuzugreifen. Der Schlüssel einer Hash−Tabelle muß immer UNIQUE sein. * Beachten Sie, daß Sie bei Hash−Tabellen keine Indexoperationen (APPEND, INSERT .. INDEX) durchführen können. Interne Hash−Tabellen lassen sich gut zum Speichern oft gelesener Stammdaten verwenden, da so wiederholte Datenbankzugriffe vermieden werden. 5.25 Tabelle vom Typ HASHED (4.0) 72 SAP_Tips Schlüsselzugriff können Sie bei jedem Tabellentyp verwenden. Jedoch ist die Performance dieser Operationen für jeden Tabellentyp anders (O(n), O(log(n), O(1)). Ein INSERT mit Schlüssel in einer Standard− oder Hash−Tabelle hat denselben Effekt wie eine APPEND−Anweisung. Mit Hash−Tabellen können Sie keine Indexoperationen (APPEND, INSERT .. Hash−Tabellen sinnvoll. **−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 5.25 Tabelle vom Typ HASHED (4.0) 73 6 String manipulation 6.1 Spezielle Operatoren im IF (CA, ...) DO−Loop mit Field−Symbols ASSIGN CHA(1) TO <C>. DO 200 TIMES. IF <C> = '(' OR <C> = ')'. "...Verarbeitung EXIT. ENDIF. ASSIGN <C>+1 TO <C>. ENDDO. Using the CA operator IF CHA(200) CA '()'. "...Verarbeitung ENDIF. Bewertung Die Nutzung der speziellen Operators CO, CA, CS ist wesentlich performanter als ein DO−Loop mit Feld−Symbolen. 6.2 String Verknüpfung Nutzung einer Verknüpfungs−FBS CALL FUNCTION 'STRING_CONCATENATE_3' EXPORTING STRING1 = T100−ARBGB STRING2 = T100−MSGNR 6 String manipulation 74 SAP_Tips STRING3 = T100−TEXT IMPORTING STRING = CLA EXCEPTIONS TOO_SMALL = 01. Nutzung des CONCATENATE statement CONCATENATE T100−ARBGB T100−MSGNR T100−TEXT INTO CLA. Bewertung Einige FBS zur String−Manipulation sollten nicht mehr verwendet werden. Bitte ersetzen durch ABAP/4 statements oder Functioen: STRING_CONCATENATE... −> CONCATENATE, STRING_SPLIT... −> SPLIT, STRING_LENGTH −> strlen(), STRING_CENTER −> WRITE...TO...CENTERED, STRING_MOVE_RIGHT −> WRITE...TO...RIGHT−JUSTIFIED, 6.3 String Verknüpfung II Notwendiger Vorlauf für Beispiel Programmiert MOVE 'Jane' TO CMA. MOVE 'Miller' TO CMB. MOVE 'New York City' TO CMC. I1 = STRLEN( CMA ). I2 = STRLEN( CMB ). MOVE 'Mrs. ' TO CHA. MOVE CMA 6.3 TO CHA+5. I1 = I1 + 6. String Verknüpfung II 75 SAP_Tips MOVE CMB TO CHA+I1. I1 = I1 + I2 + 1. MOVE 'from ' TO CHA+I1. I1 = I1 + 5. MOVE CMC TO CHA+I1. "Mrs. Jane Miller from New York City" is the final value of CHA. Nutzung des CONCATENATE statement MOVE 'Jane' TO CMA. MOVE 'Miller' TO CMB. MOVE 'New York City' TO CMC. CONCATENATE 'Mrs.' CMA CMB 'from' CMC INTO CHA SEPARATED BY SPACE. "Mrs. Jane Miller from New York City" is the final value of CHA. Bewertung Hier ist die Nutzung des CONCATENATE statement Pflicht ! 6.4 Trennen von Textstrings Nutzung SEARCH und MOVE mit Offset DATA: AREA_CODE(20), TEL_NO1(20), TEL_NO2(20). MOVE '(410)−45174−66354312' TO CMA. "CMA contains '(410)−45174−66354312' and shall be "split into AREA_CODE, " TEL_NO1, " TEL_NO2. SEARCH CMA FOR '−'. MOVE CMA(SY−FDPOS) TO AREA_CODE. I1 = SY−FDPOS + 2. 6.4 Trennen von Textstrings 76 SAP_Tips SEARCH CMA FOR '−' STARTING AT I1. I1 = I1 − 1. MOVE CMA+I1(SY−FDPOS) TO TEL_NO1. I1 = I1 + SY−FDPOS + 1. MOVE CMA+I1 TO TEL_NO2. Nutzung SPLIT statement DATA: AREA_CODE(20), TEL_NO1(20), TEL_NO2(20). MOVE '(410)−45174−66354312' TO CMA. "CMA contains '(410)−45174−66354312' and shall be "splitted into AREA_CODE, " TEL_NO1, " TEL_NO2. SPLIT CMA AT '−' INTO AREA_CODE TEL_NO1 TEL_NO2. Bewertung Die Nutzung des SPLIT−statements ist performanter * 6.5 Löschen führender Leerstellen Shifting by SY−FDPOS places. " CLA contains the string "' "Editor line n'. IF CLA CN SPACE. ENDIF. SHIFT CLA BY SY−FDPOS PLACES LEFT. SHIFT...LEFT DELETING LEADING... 6.5 Löschen führender Leerstellen 77 SAP_Tips " CLA contains the string "' "Editor line n'. SHIFT CLA LEFT DELETING LEADING SPACE. Bewertung Die Nutzung von SHIFT...LEFT DELETING LEADING... ist hier vorzuziehen! * Andere Konstructioen (mit CN und SHIFT...BY SY−FDPOS PLACES, mit CONDENSE −falls möglich−, mit CN und ASSIGN CLA+SY−FDPOS(LEN) ...) benötigen mehr Zeit. Niemals: SHIFT innerhalb WHILE−loop! 6.6 Nutzung strlen() Bestimmen Kontrollsumme über Feldlänge DATA: BEGIN OF STR, LINE TYPE X, END OF STR, CHECK_SUM TYPE I. MOVE 'KALEBVPQDSCFG' TO CLA. "DATA: BEGIN OF STR, LINE TYPE X, END OF STR, " CHECK_SUM TYPE I. "MOVE 'KALEBVPQDSCFG' TO CLA. DO 64 TIMES VARYING STR FROM CLA NEXT CLA+1. CHECK STR NE SPACE. ADD STR−LINE TO CHECK_SUM. ENDDO. Bestimmen Kontrollsumme über strlen() DATA: BEGIN OF STR, LINE TYPE X, END OF STR, CHECK_SUM TYPE I. MOVE 'KALEBVPQDSCFG' TO CLA. "DATA: BEGIN OF STR, LINE TYPE X, END OF STR, 6.6 Nutzung strlen() 78 SAP_Tips " CHECK_SUM TYPE I. "MOVE 'KALEBVPQDSCFG' TO CLA. I1 = STRLEN( CLA ). DO I1 TIMES VARYING STR FROM CLA NEXT CLA+1. CHECK STR NE SPACE. ADD STR−LINE TO CHECK_SUM. ENDDO. Bewertung Nutzen Sie die strlen( )−Funktion zur Einschränkung des DO Loops auf relvante Teile eines Feldes. Hier: Bestimmung einer Kontrollsumme 6.7 Initialisierung Initializing strings: CLEAR/TRANSLATE vs. CLEAR WITH val Initialisierung mit CLEAR/TRANSLATE DATA STRING(255). STRING is a 255 byte character field CLEAR STRING. TRANSLATE STRING USING ' *'. Notwendiger Vorlauf für Beispiel DATA STRING(255). Initialisierung mit CLEAR WITH val STRING is a 255 byte character field CLEAR STRING WITH '*'. Bewertung "CLEAR f WITH val" muss immer genutzt werden, wenn ein Feld mit Werten ungleich des Inital−Wertes belegt werden soll! 6.7 Initialisierung 79 7 Typisierung 7.1 Typisierte vs. nicht typ. Parameter Nicht typisierte Parameter DATA: M6 LIKE T006, IX TYPE I VALUE 10. PERFORM UP1 USING IX M6−DIMID M6−ZAEHL M6−ISOCODE M6−ANDEC M6−PRIMARY. FORM UP1 USING REPEAT DIMID ZAEHL ISOCODE ANDEC PRIMARY. Identischer Code links und rechts: DO REPEAT TIMES. T006−DIMID = DIMID. T006−ZAEHL = ZAEHL. T006−ISOCODE = ISOCODE. T006−ANDEC = ANDEC. T006−PRIMARY = PRIMARY. I1 = REPEAT − SY−INDEX. ENDDO. ENDFORM. Typisierte Parameter 7 Typisierung 80 SAP_Tips DATA: M6 LIKE T006, IX TYPE I VALUE 10. PERFORM UP2 USING IX M6−DIMID M6−ZAEHL M6−ISOCODE M6−ANDEC M6−PRIMARY. FORM UP2 USING REPEAT TYPE I DIMID LIKE T006−DIMID ZAEHL LIKE T006−ZAEHL ISOCODE LIKE T006−ISOCODE ANDEC LIKE T006−ANDEC PRIMARY LIKE T006−PRIMARY. Identischer Code links und rechts: DO REPEAT TIMES. T006−DIMID = DIMID. T006−ZAEHL = ZAEHL. T006−ISOCODE = ISOCODE. T006−ANDEC = ANDEC. T006−PRIMARY = PRIMARY. I1 = REPEAT − SY−INDEX. ENDDO. ENDFORM. Bewertung Wenn man die Formalparameter durch Typen spezifiziert, kann der ABAP/4−Compiler das Programm vorzeitig optimieren. Zusätzlich vermeidet man eine ungewollte Übergabe von falschen Parametern an die FORM−Routine. Wenn man große, nicht typisierte Programme hat, kann man das Typisierungstool in der Development Worbench nutzen: Aufruf Report RSPARM30 oder SE38 −> Hilfsmittel −> Typisierung 7 Typisierung 81 SAP_Tips 7.2 Typisierte vs. nicht typ. Feldsymbole Feldsymbol ohne Type FIELD−SYMBOLS: <F>. ASSIGN I1 TO <F>. I2 = <F>. I3 = <F>. I4 = <F>. Typisierte Feldsymbole FIELD−SYMBOLS: <I> TYPE I. ASSIGN I1 TO <I>. I2 = <I>. I3 = <I>. I4 = <I>. Bewertung Wenn man die Field−Symbols durch Typen spezifiziert, kann der ABAP/4−Compiler das Programm vorzeitig optimieren. 7.2 Typisierte vs. nicht typ. Feldsymbole 82 8 If, Case, ....(Performance und Wartbarkeit) 8.1 If vs. Case If IF C1A = 'A'. WRITE '1'. ELSEIF C1A = 'B'. WRITE '2'. ELSEIF C1A = 'C'. WRITE '3'. ELSEIF C1A = 'D'. WRITE '4'. ELSEIF C1A = 'E'. WRITE '5'. ELSEIF C1A = 'F'. WRITE '6'. ELSEIF C1A = 'G'. WRITE '7'. ELSEIF C1A = 'H'. WRITE '8'. ENDIF. Case CASE C1A. WHEN 'A'. WRITE '1'. WHEN 'B'. WRITE '2'. WHEN 'C'. WRITE '3'. WHEN 'D'. WRITE '4'. WHEN 'E'. WRITE '5'. WHEN 'F'. WRITE '6'. WHEN 'G'. WRITE '7'. WHEN 'H'. WRITE '8'. ENDCASE. Bewertung 8 If, Case, ....(Performance und Wartbarkeit) 83 SAP_Tips Das CASE−Statement ist übersichtlicher und sollte daher verwendet werden (WARTBARKEIT) ! CASE ist nur wenig schneller als eine IF..ELSEIf−Konstruktion. 8.2 While vs. Do DO I1 = 0. DO. IF C1A NE SPACE. EXIT. ENDIF. ADD 1 TO I1. IF I1 GT 10. C1A = 'X'. ENDIF. ENDDO. Case I1 = 0. WHILE C1A = SPACE. ADD 1 TO I1. IF I1 GT 10. C1A = 'X'. ENDIF. ENDWHILE. Bewertung Nutzen Sie WHILE anstelle von DO+EXIT−Konstruktionen − falls möglich−. WHILE ist übersichtlicher und etwas schneller. (WARTBARKEIT) 8.3 Case vs. Perform i Of ... I1 = 5. Case (I1 = 5 in this test) CASE I1. 8.2 While vs. Do 84 SAP_Tips WHEN 1. PERFORM PV1. WHEN 2. PERFORM PV2. WHEN 3. PERFORM PV3. WHEN 4. PERFORM PV4. WHEN 5. PERFORM PV5. WHEN 6. PERFORM PV6. WHEN 7. PERFORM PV7. WHEN 8. PERFORM PV8. ENDCASE. I1 = 5. Perform i Of ... (I1 = 5 in this test) PERFORM I1 OF PV1 PV2 PV3 PV4 PV5 PV6 PV7 PV8. Bewertung perform i of ist zwar schneller aber weniger übersichtlich. Beachte: I1 muß fortlaufen belegt werden (1 bis n) Wg. Wartbarkeit nicht verwenden 8.2 While vs. Do 85 9 Field Conversion 9.1 Field Types I and P Type P DATA: IP TYPE P. DO 5 TIMES. IP = SY−INDEX * 2. READ TABLE X100 INDEX IP. ENDDO. Type I DATA: IP TYPE I. DO 5 TIMES. IP = SY−INDEX * 2. READ TABLE X100 INDEX IP. ENDDO. Bewertung Nutzen Sie Datentyp I für typische Integer−Variablen − z.B. Indizes , Zähler 9.2 Literals Type C and Type I Type C SY−SUBRC = '0'. CASE SY−SUBRC. WHEN '1'. WHEN '2'. WHEN '3'. WHEN '4'. 9 Field Conversion 86 SAP_Tips ENDCASE. Type I SY−SUBRC = 0. CASE SY−SUBRC. WHEN 1. WHEN 2. WHEN 3. WHEN 4. ENDCASE. Bewertung Nutzen Sie numerische Literale oder Konstanten vom Datentyp I anstelle von Character−strings, wenn Sie Felder vom Typ I Integer−Typ P vergleichen oder diesen zuweisen. 9.3 Konstanten vom Typ F Zuweisung Literal DATA: FLOAT TYPE F. FLOAT = '3.1415926535897932'. Constant Type F CONSTANTS: PI TYPE F VALUE '3.1415926535897932'. DATA: FLOAT TYPE F. FLOAT = PI. Bewertung Konstanten werden bei Definition angegeben (constants) ! 9.3 Konstanten vom Typ F 87 SAP_Tips 9.4 Berechnungen Type N DATA: N1(15) TYPE N VALUE '123456789012345', N2(15) TYPE N VALUE '543210987654321', N3(15) TYPE N. N3 = N1 + N2. Type P DATA: P1 TYPE P VALUE '123456789012345', P2 TYPE P VALUE '543210987654321', P3 TYPE P. P3 = P1 + P2. Bewertung Use number types for arithmetic 9.5 Gemischte Datentypen Several Types DATA: F1 TYPE I VALUE 2, F2 TYPE P DECIMALS 2 VALUE '3.14', F3 TYPE F. F3 = F1 * F2. Only One Type DATA: F1 TYPE F VALUE 2, F2 TYPE F VALUE '3.14', F3 TYPE F. 9.4 Berechnungen 88 SAP_Tips F3 = F1 * F2. Bewertung Verwenden Sie in arithmetischen Operationen immer identische Datentypen ! −> Nur in wirklich begründeten Fällen davon abweichen. [Home] [SAP Tips ] [Forum] 9.4 Berechnungen 89