Upload
vuongkien
View
227
Download
3
Embed Size (px)
Citation preview
SAP's ABAP/4 Tips and TricksThese are straight from SAP, in a slightly more pleasing HTML format.
SQL Interface
Select ... Where vs. Select + Check Select with index support
Select Single vs. Select-Endselect Select ... into Table t
Select aggregates Select-Endselect vs. Array-Select
Select with view Select with select list
Select with buffer support Array Insert vs. Single-row Insert
Column Update String manipulation
Special operators in IF (CA, ...) String concatenation
String concatenation II String split Deleting leading spaces String length Initializing strings
Internal TablesBuilding sorted tables Building condensed tables Building tables without duplicates Linear vs. binary search
Different forms of key access Secondary indices
Key access to multiple lines Using explicit work areas Copying internal tables Comparing internal tables Sorting internal tables Joining internal tables Nested loops Appending a table Inserting a table Deleting duplicates Deleting a sequence of lines Deleting a set of lines
Modifying an internal table Modifying a set of lines Typing
Typed vs. untyped Parameters Typed vs. untyped Field-
Symbols If, Case, ...
If vs. Case While vs. Do Case vs. Perform i Of ...
Field ConversionField Types I and P Literals Type C and Type I
Constants Type F Arithmetic
Mixed Types
SQL Interface
Select...Where vs. Select + CheckSelect + Check Statement. Select with Where condition.SELECT * FROM SBOOK. SELECT * FROM SBOOK
CHECK: SBOOK-CARRID = 'LH' AND WHERE CARRID = 'LH' AND
SBOOK-CONNID = '0400'. CONNID = '0400'.
ENDSELECT. ENDSELECT.
microsec: 5,044 microsec: 3,886 Always specify your conditions in the Where-clause instead of checking them
yourself with Check statements. The database system can then use an index [if possible] and the network load
is considerably less.
Select single vs. Select-EndselectSelect ... Endselect. Select Single.SELECT * FROM SCARR SELECT SINGLE * FROM SCARR
WHERE CARRID = 'LH'. WHERE CARRID ='LH'.
ENDSELECT.
microsec: 2,895 microsec: 2,636 If you are interested in exactly one row of a database table or view, use the
Select Single statement instead of a Select-Endselect loop. Select Single requires one communication with the database system, whereas
Select-Endselect needs two.
Select aggregatesSelect ... Where + Check. Select using an aggregate function.
C4A = '000'. SELECT MAX( MSGNR ) FROM T100 INTO C4A
SELECT * FROM T100 WHERE SPRSL = 'D' AND
WHERE SPRSL = 'D' AND ARBGB = '00'.
ARBGB = '00'.
CHECK: T100-MSGNR > C4A.
C4A = T100-MSGNR.
ENDSELECT.
microsec: 94,287 microsec: 11,498 If you want to find the maximum, minimum, sum and average value or the
count of a database column, use a select list with aggregate functions instead of computing the aggregates yourself.
Network load is considerably less.
Select with viewNested Select statements. Select with view.SELECT * FROM DD01L SELECT * FROM DD01V
WHERE DOMNAME LIKE 'CHAR%' WHERE DOMNAME LIKE 'CHAR%'
AND AS4LOCAL = 'A'. AND DDLANGUAGE = SY-LANGU.
SELECT SINGLE * FROM DD01T ENDSELECT.
WHERE DOMNAME =
DD01L-DOMNAME
AND AS4LOCAL = 'A'
AND AS4VERS =
DD01L-AS4VERS
AND DDLANGUAGE =
SY-LANGU.
ENDSELECT.
microsec: 950,404 microsec: 195,175 To process a join, use a view instead of nested Select statements. Network load is considerably less.
Select with buffer supportSelect without buffer support. Select with buffer support.SELECT SINGLE * FROM T100 SELECT SINGLE * FROM T100
BYPASSING BUFFER WHERE SPRSL = 'D'
WHERE SPRSL = 'D' AND ARBGB = '00'
AND ARBGB = '00' AND MSGNR = '999'.
AND MSGNR = '999'.
microsec: 2,764 microsec: 99 For all frequently used, read-only tables, try to use SAP buffering. Network load is considerably less.
Column UpdateSingle-line Updates. Column Update.SELECT * FROM SFLIGHT. UPDATE SFLIGHT.
SFLIGHT-SEATSOCC = SET SEATSOCC = SEATSOCC - 1.
SFLIGHT-SEATSOCC - 1.
UPDATE SFLIGHT.
ENDSELECT.
microsec: 22,041 microsec: 4,563 Whenever possible, use column updates instead of single-row updates to
update your database tables. Network load is considerably less.
Select with index supportSelect without index support. Select with primary index support.SELECT * FROM T100. SELECT * FROM T002.
WHERE ARBGB = '00' SELECT * FROM T100
AND MSGNR = '999'. WHERE SPRSL = T002-SPRAS
ENDSELECT. AND ARBGB = '00'
AND MSGNR = '999'.
ENDSELECT.
ENDSELECT.
microsec: 1,495,282 microsec: 84,080 For all frequently used Select statements, try to use an index. You always use an index if you specify [a generic part of] the index fields
concatenated with logical Ands in the Select statement's Where clause. Note that complex Where clauses are poison for the statement optimizer in
any database system.
Select...Into Table tSelect + Append Statement. Select Into Table.
REFRESH X006. SELECT * FROM T006 INTO TABLE X006.
SELECT * FROM T006 INTO X006.
APPEND X006.
ENDSELECT.
microsec: 1,847 microsec: 919 It is always faster to use the Into Table version of a Select statement than to
use Append statements
Select-Endselect vs. Array-SelectSelect Into Table t + Loop at t. Select ... Endselect.SELECT * FROM T006 SELECT * FROM T006.
INTO TABLE X006. ENDSELECT.
LOOP AT X006.
ENDLOOP.
microsec: 1,080 microsec: 1,427 If you process your data only once, use a Select-Endselect loop instead of
collecting data in an internal table with Select Into Table. Internal table handling takes up much more space.
Select with select listSelect *. Select with select list.SELECT * FROM DD01L. SELECT DOMNAME FROM DD01L
WHERE DOMNAME LIKE 'CHAR%' INTO DD01L-DOMNAME
AND AS4LOCAL = 'A'. WHERE DOMNAME LIKE 'CHAR%'
ENDSELECT. AND AS4LOCAL = 'A'.
ENDSELECT.
microsec: 66,472 microsec: 205,433 Use a select list or a view instead of Select *, if you are only interested in
specific columns of the table. Network load is considerably less.
Array Insert vs. Single-row InsertSingle-line inserts. Array Insert.LOOP AT TAB. INSERT CUSTOMERS FROM TABLE
INSERT INTO CUSTOMERS TAB.
VALUES TAB.
ENDLOOP.
microsec: 37 microsec: 24 Whenever possible, use array operations instead of single-row operations to
modify your database tables. Frequent communication between the application program and database
system produces considerable overhead.
String manipulation
Special operators in IF (CA, ...)
DO-Loop with Field Symbols. Using the CA operator.ASSIGN CHA(1) TO <C>. IF CHA(200) CA '()'.
"...any actions
DO 200 TIMES. ENDIF.
IF <C> = '(' OR <C> = ')'.
"...any actions
EXIT.
ENDIF.
ASSIGN <C> + 1 TO <C>.
ENDDO.
microsec: 327 microsec: 11 Use the special operators CO, CA, CS, instead of programming the operations
yourself. If ABAP/4 statements are executed per character on long strings, CPU consumption
can rise substantially.
String concatenation IIMoving with offset. Use of the CONCATENATE statement." MOVE 'Jane' TO CMA. " MOVE 'Jane' TO CMA.
" MOVE 'Miller' TO CMB. " MOVE 'Miller' TO CMB.
" MOVE 'New York City' TO CMC. " MOVE 'New York City' TO CMC.
I1 = STRLEN( CMA ). CONCATENATE
I2 = STRLEN( CMB ). 'Mrs.' CMA CMB 'from' CMC
MOVE 'Mrs. ' TO CHA. INTO CHA
MOVE CMA TO CHA + 5. I1 = I1 + 6. SEPARATED BY SPACE.
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.
"Mrs. Jane Miller from New York City" is the final value of CHA.
microsec: 40 microsec: 9 Use the CONCATENATE statement instead of programming a string
concatenation of your own.
Deleting leading spacesShifting by SY-FDPOS places. Using SHIFT...LEFT DELETING
LEADING..." CLA contains the string " CLA contains the string
" ' "Editor line n'. " ' "Editor line n'.
IF CLA CN SPACE. ENDIF.
SHIFT CLA BY SY-FDPOS PLACES LEFT.
SHIFT CLA LEFT DELETING LEADING SPACE.
microsec: 4 microsec: 2 If you want to delete the leading spaces in a string, use the ABAP/4 statement
SHIFT...LEFT DELETING LEADING... Other constructions (with CN and SHIFT...BY SY-FDPOS PLACES, with
CONDENSE if possible, with CN and ASSIGN CLA + SY-FDPOS(LEN)...) are not as fast.
In any case, avoid using SHIFT inside a WHILE-loop!
Initializing strings: CLEAR/TRANSLATE vs. CLEAR WITH valInitializing with CLEAR/TRANSLATE. Initializing with CLEAR WITH val.* STRING is a 255 byte character field * STRING is a 255 byte character field
CLEAR STRING. CLEAR STRING WITH '*'.
TRANSLATE STRING USING '*'.
microsec: 20 microsec: 2 Use "CLEAR f WITH val" whenever you want to initialize a field with a value
different from the field's type-specific initial value.
String concatenationUse of a CONCATENATE function module.
Use of the CONCATENATE statement.
CALL FUNCTION 'STRING_CONCATENATE_3' CONCATENATE T100-ARBGB
EXPORTING T100-MSGNR
STRING1 = T100-ARBGB T100-TEXT INTO CLA.
STRING2 = T100-MSGNR
STRING3 = T100-TEXT
IMPORTING
STRING = CLA
EXCEPTIONS
TOO_SMALL = 01.
microsec: 67 microsec: 3 Some function modules for string manipulation have become obsolete and
should be replaced by ABAP/4 statements or functions: o STRING_CONCATENATE...->CONCATENATE o STRING_SPLIT...->SPLIT o STRING_LENGTH...->strlen() o STRING_CENTER...->WRITE...TO...CENTERED o STRING_MOVE_RIGHT...->WRITE...TO...RIGHT-JUSTIFIED
String splitUse of SEARCH and MOVE with Offset. Use of the SPLIT statement." CMA contains '(410)-45174-66354312' and
" CMA contains '(410)-45174-66354312' and
" shall be split into AREA_CODE, " shall be split into AREA_CODE,
" TEL_NO1, " TEL_NO1,
" TEL_NO2. " TEL_NO2.
SEARCH CMA FOR '-'.
MOVE CMA(SY-FDPOS) TO SPLIT CMA AT '-' INTO AREA_CODE
AREA_CODE. TEL_NO1
I1 = SY-FDPOS + 2. TEL_NO2.
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.
microsec: 28 microsec: 4 Use the SPLIT statement instead of programming a string split yourself.
String lengthGet a check-sum with length Get a check-sum with strlen()" DATA: BEGIN OF STR, LINE TYPE X, END OF STR.
" DATA: BEGIN OF STR, LINE TYPE X, END OF STR.
" ' CHECK_SUM TYPE I. " ' CHECK_SUM TYPE I.
" MOVE 'KALEBVPQDSCFG' TO CLA. " MOVE 'KALEBVPQDSCFG' TO CLA.
I1 = STRLEN( CLA ).
DO 64 TIMES VARYING STR FROM CLA NEXT CLA+1.
DO I1 TIMES VARYING STR FROM CLA NEXT CLA+1.
CHECK STR NE SPACE. CHECK STR NE SPACE.
ADD STR-LINE TO CHECK_SUM. ADD STR-LINE TO CHECK_SUM.
ENDDO. ENDDO.
microsec: 178 microsec: 55 Use the strlen() function to restrict the DO loop to the relevant part of the field,
eg. when determining a check-sum.
Internal TablesBuilding a sorted internal table: READ/INSERT vs. APPEND/SORT
One-step approach: READ/INSERT.
Two-step approach: APPEND, then SORT.
* TAB_DEST is filled with 1000 entries
* TAB_DEST is filled with 1000 entries
REFRESH TAB_DEST. REFRESH TAB_DEST.
LOOP AT TAB_SRC. LOOP AT TAB_SRC.
READ TABLE TAB_DEST APPEND TAB_SRC TO TAB_DEST.
WITH KEY K = TAB_SRC-K ENDLOOP.
BINARY SEARCH. SORT TAB_DEST BY K.
INSERT TAB_SRC INTO TAB_DEST
INDEX SY-TABIX.
ENDLOOP.
microsec: 22,223 microsec: 10,745 If the amount of data is small (<20 entries), or if you need read-access to the
internal table while it is being filled, the one-step approach using READ/INSERT is the right choice.
If, however, the data amount is larger and you need read-access only to the completely-filled table, the two-step algorithm is preferable
Building unique sorted tables: READ/INSERT vs. APPEND/SORT/DELETE
One step approach Three-steps: copy, sort, delete duplicates.
* TAB_SRC contains 1000 entries, of which * TAB_SRC contains 1000 entries, of which
* 500 are different. * 500 are different.
REFRESH TAB_DEST. REFRESH TAB_DEST.
LOOP AT TAB_SRC. LOOP AT TAB_SRC.
READ TABLE TAB_DEST APPEND TAB_SRC TO TAB_DEST.
WITH KEY K = TAB_SRC ENDLOOP.
BINARY SEARCH. SORT TAB_DEST BY K.
IF SY-SUBRC <> 0. DELETE ADJACENT DUPLICATES FROM
INSERT TAB_SRC INTO TAB_DEST TAB_DEST COMPARING K.
INDEX SY-TABIX.
ENDIF.
ENDLOOP.
microsec: 13,393 microsec: 12,806 If the data amount is small (<20 entries), or if you need read-access to the
internal table while it is being filled, the one-step approach using READ/INSERT is the right choice.
If, however, the data amount is larger and you need read-access only to the completely-filled table, the three-step algorithm is preferable.
Key access: implicit versus explicit key field specificationAccess via implicit default key. Access via key specified explicitly.* Table TAB is filled with 30 entries of * Table TAB is filled with 30 entries of
* 500 bytes each. * 500 bytes each.
* The READ ends with SY-SUBRC = 4 * The READ ends with SY-SUBRC = 4
MOVE SPACE TO TAB. READ TABLE TAB WITH KEY K = 'X'
TAB-K = 'X'. BINARY SEARCH.
READ TABLE TAB BINARY SEARCH.
microsec: 14 microsec: 4 If possible, specify the key fields for read access explicitly. Otherwise, the key fields have to be computed dynamically by the run-time
system.
Key access to multiple lines: LOOP/CHECK versus LOOP...WHEREKey access with LOOP/CHECK. Key access with LOOP...WHERE.* Table TAB is filled with 100 entries * Table TAB is filled with 100 entries
* of 500 bytes each, * of 500 bytes each,
* 5 entries of which match the key conditions
* 5 entries of which match the key conditions
LOOP AT TAB. LOOP AT TAB WHERE K = KVAL.
CHECK TAB-K = KVAL. " ...
" ... ENDLOOP.
ENDLOOP.
microsec: 697 microsec: 123 LOOP...WHERE is faster than LOOP/CHECK because LOOP...WHERE
evaluates the specified condition internally. As with any logical expressions, the performance is better if the operands of a
comparison share a common type. The performance can be further enhanced if LOOP...WHERE is combined with
FROM i1 and/or TO i2, if possible
Copying internal tablesPedestrian way to copy internal tables. Let the kernel do the work...* Table TAB_SRC is filled with 100 entries * Table TAB_SRC is filled with 100 entries
* of 100 bytes each. * of 100 bytes each.
REFRESH TAB_DEST. TAB_DEST[] = TAB_SRC[].
LOOP AT TAB_SRC INTO TAB_DEST.
APPEND TAB_DEST.
ENDLOOP.
microsec: 370 microsec: 119 Internal tables can be copied by MOVE just like any other data object. If an internal table itab has a header line, the table itself is accessed by itab[].
Sorting internal tablesSort internal table with default sort key. Sort with sort key specified explicitly.* Table TAB is filled with 100 entries * Table TAB is filled with 100 entries
* of 500 bytes each. * of 500 bytes each.
SORT TAB. SORT TAB BY K.
microsec: 1,318 microsec: 417 The more restrictively you specify the sort key, the faster the program will run. Therefore, specify the sort key as restrictively as possible.
Nested loops at two sorted tables
Straightforward nested loop. More sophisticated loop: parallel cursors.
* Table TAB1 is filled with 100 entries * Table TAB1 is filled with 100 entries
* of 100 bytes each. * of 100 bytes each.
* Table TAB2 is filled with * Table TAB2 is filled with
* 10 * 100 = 1000 entries of 100 bytes each. * 10 * 100 = 1000 entries of 100 bytes each.
* Tables TAB1 and TAB2 are assumed to be
* sorted by K in ascending order.
LOOP AT TAB1. I2 = 1.
LOOP AT TAB2 WHERE K = TAB1-K. LOOP AT TAB1.
" ... LOOP AT TAB2 FROM I2.
ENDLOOP. IF TAB2-K <> TAB1-K.
ENDLOOP. I2 = SY-TABIX.
EXIT.
ENDIF.
" ...
ENDLOOP.
ENDLOOP.
microsec: 139,964 microsec: 3,915 If TAB1 has n1 entries and TAB2 has n2 entries, the time needed for the
nested loop with the straightforward algorithm is O(n1 * n2), whereas the parallel cursor approach takes only O(n1 + n2) time.
The above parallel cursor algorithm assumes that TAB2 contains only entries also contained in TAB1.
If this assumption does not hold, the parallel cursor algorithm gets slightly more complicated, but its performance characteristics remain the same.
Inserting an internal table into another internal tablePedestrian way to insert a table. Let the kernel do the work...* Table TAB_SRC and TAB_DEST are both
* Table TAB_SRC and TAB_DEST are both
* filled with 500 entries of 100 bytes each. * filled with 500 entries of 100 bytes each.
* TAB_SRC is inserted in a single step into
* TAB_SRC is inserted in a single step into
* TAB_DEST at index IDX. * TAB_DEST at index IDX.
IDX = 250. IDX = 250.
LOOP AT TAB_SRC. INSERT LINES OF TAB_SRC INTO
INSERT TAB_SRC INTO TAB_DEST TAB_DEST INDEX IDX.
INDEX IDX.
ADD 1 TO IDX.
ENDLOOP.
microsec: 5,802 microsec: 1,194 With the new INSERT variant INSERT LINES OF itab1 TO itab2 INDEX idx,
the task of inserting a table into another table can be transferred to the kernel.
Deleting a sequence of lines from an internal tablePedestrian way to delete a sequence of lines. Let the kernel do the work...
* Table TAB_DEST is filled with 1000 entries * Table TAB_DEST is filled with 1000 entries
* of 500 bytes each, and lines 450 to 550 are * of 500 bytes each, and lines 450 to 550 are
* to be deleted * to be deleted
DO 101 TIMES. DELETE TAB_DEST FROM 450 TO 550.
DELETE TAB_DEST INDEX 450.
ENDDO.
microsec: 1,301 microsec: 77 With the new DELETE variant DELETE itab FROM...TO..., the task of deleting
a sequence of lines can be transferred to the kernel.
Modifying selected components of an internal tableModifying all components. Modifying selected components only.* Table TAB is filled with 5000 entries of 500
* Table TAB is filled with 5000 entries of 500
* bytes each. Actually, only the 8 bytes of the
* bytes each. Only the 8 bytes of the selected
* component DATE are modified. * component DATE are modified.
LOOP AT TAB. WA-DATE = SY-DATUM.
TAB-DATE = SY-DATUM. LOOP AT TAB.
MODIFY TAB. MODIFY TAB FROM WA
ENDLOOP. TRANSPORTING DATE.
ENDLOOP.
microsec: 6,919 microsec: 2,717 With the MODIFY variant MODIFY itab...TRANSPORTING f1 f2... the task of
updating a line of an internal table can be accelerated. The longer the table line is, the larger the speed-up is. The effect increases for tables
with complex structured line types.
Building a condensed, sorted table: READ/INSERT vs. COLLECT/SORT
COLLECT semantics using READ BINARY. Collect via COLLECT.
* Table TAB_SRC is filled with 10,000 entries,
* Table TAB_SRC is filled with 10,000 entries
* 5,000 of which have different keys * 5,000 of which have different keys
LOOP AT TAB_SRC. LOOP AT TAB_SRC.
READ TABLE TAB_DEST COLLECT TAB_SRC INTO TAB_DEST.
WITH KEY K = TAB_SRC-K ENDLOOP.
BINARY SEARCH. SORT TAB_DEST BY K.
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.
ELSE.
INSERT TAB_SRC INTO TAB_DEST
INDEX SY-TABIX.
ENDIF.
ENDLOOP.
microsec: 299,948 microsec: 132,617 If you need the COLLECT semantics, DO use COLLECT! READ BINARY runs in O(log²(n)) time, and the internal table's index must be
adjusted with each INSERT. COLLECT, however, uses a hash algorithm and is therefore independent of
the number of entries (ie. O(1)) and does not need to maintain a table index. If you need the final data sorted, sort it after all data has been collected.
If the amount of data is small, the READ/INSERT approach isn't bad, but for larger amounts of data (>1000), COLLECT is much faster.
Caution: When you fill an internal table, do not use COLLECT in combination with any other table-filling statements (APPEND, INSERT, MODIFY, SELECT * INTO TABLE and/or SELECT * APPENDING TABLE). If you mix COLLECT with the other statements, COLLECT cannot use its hash algorithm. In this case, COLLECT resorts to a normal linear search, which is dramatically slower: O(n).
Linear search vs. binary searchLinear search of an internal table. Binary search of an internal table.
* Table TAB is filled with 1000 entries * Table TAB is filled with 1000 entries
* of 100 bytes each. * of 100 bytes each.
* The READ ends with SY-SUBRC = 4 * The READ ends with SY-SUBRC = 4
READ TABLE TAB WITH KEY K = 'X'. READ TABLE TAB WITH KEY K = 'X'
BINARY SEARCH.
microsec: 545 microsec: 7 If internal tables are assumed to have many (>20) entries, a linear search
through all entries is very time-consuming. Try to keep the table ordered and use binary search. If TAB has n entries, linear search runs in O(n) time, whereas binary search takes only
O(log²(n)).
Creating a secondary index to avoid linear searchNo secondary index => linear search. Binary search using secondary index.* Table TAB is filled with 1000 entries. * Table TAB is filled with 1000 entries.
* The READ locates the 500th entry. * The READ locates the 500th entry.
READ TABLE TAB WITH KEY DATE = READ TABLE TAB_INDEX
SY-DATUM. WITH KEY DATE = SY-DATUM
IF SY-SUBRC = 0. BINARY SEARCH.
" ... IF SY-SUBRC = 0.
ENDIF. READ TABLE TAB INDEX
TAB_INDEX-INDX.
" ...
ENDIF.
microsec: 268 microsec: 10 If you need access an internal table with different keys repeatedly, keep your
own secondary indices. With a secondary index, you can replace a linear search with a binary search
plus an index access.
Using an explicit work area instead of filling the header lineTable operation via header line. Table operation via explicit work area.
* The line width of table TAB is 500 bytes. * The line width of table TAB is 500 bytes.
TAB = TAB_WA. APPEND TAB_WA TO TAB.
APPEND TAB.
microsec: 7 microsec: 3 Avoid unnecessary MOVEs by using the explicit work area operations
o APPEND wa TO tab. o INSERT wa INTO tab. o COLLECT wa INTO tab. o MODIFY tab FROM wa. o READ TABLE tab INTO wa. o LOOP AT tab INTO wa.
where appropriate.Comparing internal tables
Pedestrian way to compare internal tables. Let the kernel do the work...
* Tables TAB1 and TAB2 are each filled * Tables TAB1 and TAB2 are each filled
* with 100 entries of 100 bytes each. * with 100 entries of 100 bytes each.
DESCRIBE TABLE: TAB1 LINES L1, IF TAB1[] = TAB2[].
TAB2 LINES L2. " ...
IF L1 <> L2. ENDIF.
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.
microsec: 660 microsec: 202 Internal tables can be compared in logical expressions just like other data
objects. Two internal tables are equal if
1. they have the same number of lines and 2. each pair of corresponding lines is equal.
If an internal table itab has a header line, the table itself is accessed by itab[].
Joining two sorted internal tables with unique keysNaive join: loop tab1, read tab2 with key.
More sophisticated: use parallel cursors.
* Table TAB1 is filled with 1000 entries * Table TAB1 is filled with 1000 entries
* of 100 bytes each. * of 100 bytes each.
* Table TAB2 is filled with 300 entries * Table TAB2 is filled with 300 entries
* of 100 bytes each. * of 100 bytes each.
* Table TAB2 is assumed to be sorted by * Table TAB2 is assumed to be sorted by
* K in ascending order. * K in ascending order.
LOOP AT TAB1. I2 = 1.
READ TABLE TAB2 LOOP AT TAB1.
WITH KEY K = TAB1-K READ TABLE TAB2 INDEX I2.
BINARY SEARCH. IF SY-SUBRC <> 0. EXIT. ENDIF.
IF SY-SUBRC = 0. IF TAB2-K = TAB1-K.
" ... " ...
ENDIF. ADD 1 TO I2.
ENDLOOP. ENDIF.
ENDLOOP.
microsec: 10,978 microsec: 3,766 If TAB1 has n1 entries and TAB2 has n2 entries, the time needed for joining
TAB1 and TAB2 with the straightforward algorithm is O(n1*log²(n2)), whereas the parallel cursor approach takes only O(n1 + n2) time.
The above parallel cursor algorithm assumes that TAB2 is a secondary table containing only entries also contained in primary table TAB1.
If this assumption does not hold, the parallel cursor algorithm gets slightly more complicated, but its performance characteristics remain the same.
Appending an internal table to another internal tablePedestrian way to append a table. Let the kernel do the work...* Table TAB_SRC and TAB_DEST are * Table TAB_SRC and TAB_DEST are
both both
* filled with 500 entries of 100 bytes each. * filled with 500 entries of 100 bytes each.
* TAB_SRC is appended line by line to * TAB_SRC is appended line by line to
* TAB_DEST. * TAB_DEST.
LOOP AT TAB_SRC. APPEND LINES OF TAB_SRC TO
APPEND TAB_SRC TO TAB_DEST. TAB_DEST.
ENDLOOP.
microsec: 2,405 microsec: 1,121 With the new APPEND variant APPEND LINES OF itab1 TO itab2, the task of
appending a table to another table can be transferred to the kernel.
Deleting duplicate entries from a sorted internal tablePedestrian way to delete duplicates. Let the kernel do the work...* Table TAB_DEST is filled with 1000 entries
* Table TAB_DEST is filled with 1000 entries
* of 100 bytes each and contains 500 pairs
* of 100 bytes each and contains 500 pairs
* of duplicates. * of duplicates.
READ TABLE TAB_DEST INDEX 1 INTO DELETE ADJACENT DUPLICATES FROM
PREV_LINE. TAB_DEST COMPARING K.
LOOP AT TAB_DEST FROM 2.
IF TAB_DEST = PREV_LINE.
DELETE TAB_DEST.
ELSE.
PREV_LINE = TAB_DEST.
ENDIF.
ENDLOOP.
microsec: 11,597 microsec: 1,707 With the new DELETE variant DELETE ADJACENT DUPLICATES, the task of
deleting duplicate entries can be transferred to the kernel.
Deleting a set of lines specified by a WHERE conditionPedestrian way to delete a set of lines. Let the kernel do the work...* Table TAB_DEST is filled with 1000 entries
* Table TAB_DEST is filled with 1000 entries
* of 500 bytes each, 250 of which match the
* of 500 bytes each, 250 of which match the
* WHERE condition. * WHERE condition.
LOOP AT TAB_DEST WHERE K = KVAL. DELETE TAB_DEST WHERE K = KVAL.
DELETE TAB_DEST.
ENDLOOP.
microsec: 6,919 microsec: 2,717 With the new DELETE variant DELETE itab [FROM...] [TO...] WHERE..., the
task of deleting a set of lines can be transferred to the kernel. If possible, WHERE should be used together with the FROM... and/or TO... to
enhance the performance even more. The performance gain when using
DELETE itab WHERE...
instead of LOOP AT itab WHERE...
DELETE itab.ENDLOOP.
increases with the number of entries the internal table contains and the number of lines to be deleted.
Modifying selected components of a set of linesModifying all components. Modifying selected components only.* Table TAB is filled with 100 entries. * Table TAB is filled with 100 entries.
* A line has two components, a FLAG of type
* A line has two components, a FLAG of type
* C and an integer table INTTAB with 20 * C and an integer table INTTAB with 20
* entries each. The FLAG is switched on * entries each. The FLAG is switched on
* for all 100 lines. * for all 100 lines.
LOOP AT TAB. TAB-FLAG = 'X'.
IF TAB-FLAG IS INITIAL. MODIFY TAB TRANSPORTING FLAG
TAB-FLAG = 'X'. WHERE FLAG IS INITIAL.
MODIFY TAB.
ENDIF.
ENDLOOP.
microsec: 6,919 microsec: 2,717 With the MODIFY variant MODIFY itab...TRANSPORTING f1 f2... WHERE
cond the task of updating a set of lines of an internal table can be accelerated considerably. Especially if tables embedded in the lines can be ignored while updating, the speed-up is high.
TypingTyped vs. untyped Parameters
Untyped parameters. Typed parameters.PERFORM UP1 USING IX M6-DIMID PERFORM UP2 USING IX M6-DIMID
M6-ZAEHL M6-ISOCODE M6-ANDEC M6-ZAEHL M6-ISOCODE M6-ANDEC
M6-PRIMARY. M6-PRIMARY.
FORM UP1 USING FORM UP2 USING
REPEAT REPEAT TYPE I
DIMID DIMID LIKE T006-DIMID
ZAEHL ZAEHL LIKE T006-ZAEHL
ISOCODE ISOCODE LIKE T006-ISOCODE
ANDEC ANDEC LIKE T006-ANDEC
PRIMARY. PRIMARY LIKE T006-PRIMARY.
* Identical source code left and right: * Identical source code left and right:
DO REPEAT TIMES. DO REPEAT TIMES.
T006-DIMID = DIMID. T006-DIMID = DIMID.
T006-ZAEHL = ZAEHL. T006-ZAEHL = ZAEHL.
T006-ISOCODE = ISOCODE. T006-ISOCODE = ISOCODE.
T006-ANDEC = ANDEC. T006-ANDEC = ANDEC.
T006-PRIMARY = PRIMARY. T006-PRIMARY = PRIMARY.
I1 = REPEAT - SY-INDEX. I1 = REPEAT - SY-INDEX.
ENDDO. ENDDO.
ENDFORM. ENDFORM.
microsec: 98 microsec: 53 If you specify the type for formal parameters in your source code, the ABAP/4
compiler can optimize your code more thoroughly. In addition, the risk of using the wrong sequence of parameters in a Perform
statement is much less. If you have large 'untyped' programs, use the automatic typing facility of the
Development Workbench.
Typed vs. untyped Field-SymbolsField-Symbol without type. Typed Field-Symbol.FIELD-SYMBOLS: <F>. FIELD-SYMBOLS: <I> TYPE I.
ASSIGN I1 TO <F>. ASSIGN I1 TO <I>.
I2 = <F>. I2 = <I>.
I3 = <F>. I3 = <I>.
I4 = <F>. I4 = <I>.
microsec: 5 microsec: 3 If you specify the type of field-symbols and formal parameters in your source
code, the ABAP/4 compiler can better optimize your code.
If, Case, ...If vs. Case
If. Case.IF C1A = 'A'. WRITE '1'. CASE C1A.
ELSEIF C1A = 'B'. WRITE '2'. WHEN 'A'. WRITE '1'.
ELSEIF C1A = 'C'. WRITE '3'. WHEN 'B'. WRITE '2'.
ELSEIF C1A = 'D'. WRITE '4'. WHEN 'C'. WRITE '3'.
ELSEIF C1A = 'E'. WRITE '5'. WHEN 'D'. WRITE '4'.
ELSEIF C1A = 'F'. WRITE '6'. WHEN 'E'. WRITE '5'.
ELSEIF C1A = 'G'. WRITE '7'. WHEN 'F'. WRITE '6'.
ELSEIF C1A = 'H'. WRITE '8'. WHEN 'G'. WRITE '7'.
ENDIF. WHEN 'H'. WRITE '8'.
ENDCASE.
microsec: 4 microsec: 3 CASE statements are clearer and a little faster than If constructions.
Case vs. Perform i Of...Case. Perform i Of.* (I1 = 5 in this test) * (I1 = 5 in this test)
CASE I1. PERFORM I1 OF
WHEN 1. PERFORM PV1. PV1
WHEN 2. PERFORM PV2. PV2
WHEN 3. PERFORM PV3. PV3
WHEN 4. PERFORM PV4. PV4
WHEN 5. PERFORM PV5. PV5
WHEN 6. PERFORM PV6. PV6
WHEN 7. PERFORM PV7. PV7
WHEN 8. PERFORM PV8. PV8
ENDCASE.
microsec: 4 microsec: 3
A very fast way to call a certain routine using a given index is the Perform i Of... statement.
While vs. DoDo. While.I1 = 0. I1 = 0.
DO. WHILE C1A = SPACE.
IF C1A NE SPACE. EXIT. ENDIF. ADD 1 TO I1.
ADD 1 TO I1. IF I1 GT 10. C1A = 'X'. ENDIF.
IF I1 GT 10. C1A = 'X'. ENDIF. ENDWHILE.
ENDDO.
microsec: 3 microsec: 3 If you can use WHILE instead of a DO + EXIT construction, then do so. WHILE is easier to understand and faster to execute.
Field ConversionField Types I and P
Type P. Type I.DATA: IP TYPE P. DATA: IP TYPE I.
DO 5 TIMES. DO 5 TIMES.
IP = SY-INDEX * 2. IP = SY-INDEX * 2.
READ TABLE X100 INDEX IP. READ TABLE X100 INDEX IP.
ENDDO. ENDDO.
microsec: 37 microsec: 19 Use Fields of Type I for typical integer variables like indices.
Constants Type FLiteral Type C. Constant Type F.DATA: CONSTANTS:
FLOAT TYPE F. PI TYPE F
VALUE '3.1415926535897932'.
DATA:
FLOAT TYPE F.
FLOAT = '3.1415926535897932'. FLOAT = PI.
microsec: 4 microsec: 1 Use correctly typed constants instead of literals.
Mixed TypesSeveral Types. Only One Type.DATA: F1 TYPE I VALUE 2, DATA: F1 TYPE F VALUE 2,
F2 TYPE P DECIMALS 2 VALUE '3.14', F2 TYPE F VALUE '3.14',
F3 TYPE F. F3 TYPE F.
F3 = F1 * F2. F3 = F1 * F2.
microsec: 14 microsec: 1 Don't mix types unless absolutely necessary.
Literals Type C and Type IType C. Type I.SY-SUBRC = '0'. SY-SUBRC = 0.
CASE SY-SUBRC. CASE SY-SUBRC.
WHEN '1'. WHEN '1'.
WHEN '2'. WHEN '2'.
WHEN '3'. WHEN '3'.
WHEN '4'. WHEN '4'.
ENDCASE. ENDCASE.
microsec: 10 microsec: 2 Use numeric literals or named constants with a number type instead of
character strings if you are dealing with type I or integer type C fields.
ArithmeticType N. Type P.DATA: DATA:
N1(15) TYPE N P1(15) TYPE P
VALUE '123456789012345', VALUE '123456789012345',
N2(15) TYPE N P2(15) TYPE P
VALUE '543210987654321'. VALUE '543210987654321'.
N3(15) TYPE N. P3 TYPE P.
N3 = N1 + N2. P3 = P1 + P2.
microsec: 30 microsec: 3 Use number types for arithmetic.