Monday, June 2, 2014

Do's and Don't Do's in Open SQLABAP

Do's & Don't in ABAP programming using SELECT statement  



Objective:

The idea behind this document came when I was reading very excellent blog about OpenSQL A complete guide to OpenSQL statements  which helps developers in writing query using OpenSQL.
However that blog does not talks much about the common mistakes which mostly developers do in writing query results in rework for the defects/performance when object is delivered.
So, I collected some common errors which can be avoided during the development so that an efficient code is delivered with high performance.

Let me know if there is more we can add here!

Usage of SELECT statement:

a) SELECT with Primary key/Secondary Index

Ensure that data is selected with Primary key /Secondary index support with the fields in the select statement’s WHERE clause in the same order as fields in the index.

Wrong ApproachRight Approach
SELECT * FROM mara INTO TABLE itab WHERE mtart EQ 'ROH' AND matnr EQ '000001102'
SELECT * FROM mara INTO TABLE itab WHERE matnr EQ '000001102' AND mtart EQ 'ROH'

b) Avoid SELECT with Negative Clause

The database system only supports queries that describe the result in positive terms, for example, EQ or LIKE. It does not support negative expressions like NE or NOT LIKE. 

Wrong ApproachRight Approach
SELECT * FROM mara INTO TABLE itab WHERE mtart EQ 'ROH' AND ersda NE sy-datum

SELECT * FROM mara INTO TABLE itab WHERE mtart EQ 'ROH' AND ( ersda LT sy-datum OR ersda GT sy-datum )

NOTE: If possible, avoid using the NOT operator in the WHERE clause, because it is not supported by database indexes; invert the logical expression instead.

c) SELECT with WHERE Clause fields – Reading single record

When using select for a single record access, always keep in mind, is selection based on Primary key or Non Primary key field?

i) When based on Non-Primary Key

Wrong ApproachRight Approach
SELECT SINGLE matnr FROM mara INTO lv_matnr WHERE vbeln = '0001500080'.

SELECT matnr UP TO 1 ROWS FROM mara INTO lv_matnr WHERE vbeln = '0001500080'.
ENDSELECT.

ii) When based on Primary Key

Wrong ApproachRight Approach
SELECT audat vbtyp UP TO 1 ROWS FROM vbak INTO (lv_audat, lv_vbtyp)
WHERE vbeln = '0001500080'

SELECT SINGLE audat vbtyp FROM vbak INTO (lv_audat, lv_vbtyp) WHERE vbeln = '0001500080'

d) Select with JOIN Clause

Select with JOINS instead of nested select statements to read data from logically related tables. If the number of records to be fetched in a JOIN clause is more than five ensure that the join fields are the key fields. Always limit tables in a join to three tables

Wrong ApproachRight Approach
SELECT vbeln auart FROM vbak INTO ls_vbak
WHERE vbeln BETWEEN '0000000001' AND '0000002000'.
    SELECT posnr matnr kwmeng FROM vbap INTO ls_vbap
        WHERE vbeln = ls_vbak-vbeln AND matkl = '000000001'.
           SELECT etenr FROM vbep INTO ls_vbep
              WHERE vbeln = ls_vbak-vbeln AND posnr = ls_vbap-posnr.
* ..... logic here ........*
ENDSELECT.
ENDSELECT.
ENDSELECT.

SELECT v~vbeln v~auart p~posnr p~matnr p~kwmeng e~etenr
INTO TABLE itab
FROM vbak AS v INNER JOIN vbap
AS p ON v~vbeln = p~vbeln
INNER JOIN vbep AS e ON p~vbeln = e~vbeln
AND p~posnr = e~posnr
WHERE v~vbeln BETWEEN '0000000001'
AND '0000002000'.

NOTE: When using views or the join construct the database can also better optimize the disk accesses

e) SELECT * Vs. SELECT fields

Always select fields only instead of select *, when number of fields < 1/3rd of total fields in table or no. of fields getting selected is less than or equal to 16.

Wrong ApproachRight Approach
SELECT * FROM spfli INTO ls_spfli WHERE carrid ='AA'.
* ..... logic here ........*
* ..... logic here ........*
SELECT carrid connid cityfrom INTO (lv_carrid, lv_connid, lv_cityfrom) FROM spfli WHERE carrid = 'AA'.
* ..... logic here ........*
* ..... logic here ........*

f) SELECT using Aggregate functions

Select using an aggregate function (SUM, MIN, MAX, COUNT) instead of computing the aggregates yourself.

For Example: To list the number of accounting document headers (rows in BKPF) with document type ‘EM’ for FY1999, for each of the company codes

Wrong ApproachRight Approach
SELECT mandt bukrs FROM bkpf WHERE blart = 'EM'
AND gjahr = '1999'.
* ..... logic here to count .....*
SELECT mandt bukrs COUNT(*) FROM bkpf WHERE blart = 'EM' AND gjahr = '1999' GROUP BY mandt bukrs.

NOTE: When you do the calculations in your program, you need to read all data rows from the d/base into the program (over the network) causing a considerable load on the network.

g) SELECT INTO Table Version

Always prefer to use SELECT INTO TABLE Clause rather than using SELECT with Append statement.

Wrong ApproachRight Approach
SELECT * FROM mara INTO ls_mara WHERE matnr BETWEEN '000000000060000000' AND '000000000060000335'.
APPEND ls_mara TO itab.
ENDSELECT.
SELECT * FROM mara INTO TABLE itab WHERE matnr BETWEEN '000000000060000000' AND '000000000060000335'.

h) Avoid Complex WHERE Clause(1)

Complex WHERE clauses should be avoided always because it confuses database optimizer. One should avoid -OR- construct in WHERE clause instead use IN

Wrong ApproachRight Approach
SELECT * FROM ekpo INTO TABLE lt_ekpo WHERE ebeln IN '001' AND aedat IN s_date AND
( bukrs = '3000' OR bukrs = '3500' OR bukrs = '5500').
* ---- logic here ---- *
SELECT * FROM ekpo INTO TABLE  t_ekpo WHERE ebeln IN s_ebeln AND aedat IN s_date AND bukrs IN ('3000', '3500', '5000').
* ---- logic here ---- *

i) Avoid Complex WHERE Clause(2)

Do NOT use the '>= AND <= construct' but use BETWEEN construct instead. It will result in improved performance.

Wrong ApproachRight Approach
SELECT * FROM mara WHERE matnr IN s_matnr AND ersda >= sy-datum AND
ersda <= '20141231'.
* ---- logic here ---- *
SELECT * FROM mara WHERE matnr IN s_matnr AND ersda BETWEEN sy-datum AND '20141231'.
* ---- logic here ---- *

j) Select statements on Cluster Tables

Do not use select statement on cluster tables as it creates performance issues. Alternatively, we should access Secondary Index tables.
For example, BSEG access

Wrong ApproachRight Approach
SELECT bukrs belnr ghahr INTO TABLE itab FROM besg WHERE kunnr IN s_kunnr.
* secondary index tables access
SELECT bukrs belnr ghahr INTO TABLE itab FROM bsid WHERE kunnr IN s_kunnr.

NOTE: SAP has provided many secondary index tables for operation on FI-GL tables. Also, it is always a better option to buffer the data of a pool table in the application once and process it in the program rather then going to database again and again.

TIPS:
  • In FI-GL the secondary index tables BSIS, BSAS, BSIK, BSAK, BSID and BSAD often are a better starting point to retrieve accounting document information than using the traditional method (directly going from BKPF (accounting document header table) to the BSEG table)
  • FI-GL programs which are normally run for a specific vendor account number it is better to start accessing BSAK and BSIK first, before accessing BKPF and BSEG, instead of starting with the BKPF table. As the BKPF table does not contain vendor account number information, a lot of accounting documents are read which are not needed as they do not match the vendor account specified by the user, in case BKPF is used as starting point. In case BSAK and BSIK are used, only the accounting documents matching the specified vendor account number will be read, reducing the runtime from several hours to minutes.