3
votes

I have declare an internal table like:

DATA: wa_collectoraction TYPE zcollectoraction,
  it_collectoraction LIKE STANDARD TABLE OF zcollectoraction.

Then I fill the table with:

SELECT bukrs kunnr yearmonth MAX( dat ) AS dat
FROM zcollectoraction
  INTO CORRESPONDING FIELDS OF TABLE it_collectoraction
WHERE bukrs IN so_bukrs AND
      kunnr IN so_kunnr AND
      dat   IN so_date
GROUP BY bukrs kunnr yearmonth.

and finally I have the following loop

LOOP AT it_collectoraction INTO wa_collectoraction.
PERFORM progress_bar USING 'Retrieving data...'(035)
                           sy-tabix
                           i_tab_lines.
"Get the MAX TIME for all lines in order to cover the case we have more than 1 line."
SELECT SINGLE * FROM zcollectoraction
    INTO CORRESPONDING FIELDS OF wa_collectoraction
  WHERE bukrs = wa_collectoraction-bukrs AND
        kunnr = wa_collectoraction-kunnr AND
        dat   = wa_collectoraction-dat   AND
        time  = ( SELECT MAX( time ) AS time
                    FROM zcollectoraction
                    WHERE bukrs = wa_collectoraction-bukrs AND
                          kunnr = wa_collectoraction-kunnr AND
                          dat   = wa_collectoraction-dat ).

MODIFY it_collectoraction FROM wa_collectoraction.
ENDLOOP.

This loop is doing 5 minutes for 3000 records. Can someone tell me what to do in order to be faster?  

Thanks in advance

4
Which NetWeaver version are you running on?user5653854
what type of database are you using?András
Component Version: SAP ECC 6.0. DATABASE SYSTEM: DB6 sap versions: 700, 710, 701, 702, 711, 720, 730ekekakos
The loop itself is fine. But what kind of grudge do you hold against your database that you're trying to kill it so cruelly? ;-)vwegert
vwegert, what I am trying to do, I explain it below. Well, let me tell you. In the select I am taking the specific fields of the max date of the month. Then I select all the fields of the record with the max time because there is a big possibility to have more than 1 record as a max date. You can see an example below. Thanksekekakos

4 Answers

4
votes

The best tool to analyze a standalone report's performance is ST12, so if you have the chance, trace it.
Without a trace, we have to guess, the biggest problem is either the SELECT with the subSELECT, or the MODIFY.

1) SELECTs in a LOOP are always slow

Here you actually make two for every line in it_collectoraction.

Try reducing the number of SELECTs

Depending on the number of lines with the same dat, it might be much faster to replace the SELECT in the LOOP with a SELECT with FOR ALL ENTRIES from zcollectoraction outside the LOOP, and find the MAX(time) on ABAP side.

Index coverage

Seems to be fine.

2) MODIFY is slow on STANDARD tables

You have to sieve through the whole table just to find the relevant line. If you define it_collectoraction as SORTED, this will be much faster. If you use a field symbol in the LOOP, it can be avoided altogether.

Coding

Replace your LOOP with this:

TYPES: BEGIN OF tty_coll_act,
        bukrs TYPE burks,
        kunnr TYPE kunnr,
        dat   TYPE dat,
        time  TYPE time,
      END OF tty_coll_act.

DATA: lt_coll_act TYPE TABLE OF tty_coll_act,
      ls_coll_act LIKE LINE OF lt_coll_act.

FIELD-SYMBOLS: <fs_collectoraction> LIKE LINE OF it_collectoraction.

SELECT bukrs kunnr dat time
    INTO TABLE lt_coll_act
    FROM zcollectoraction
    FOR ALL ENTRIES IN it_collectoraction
    WHERE bukrs = wa_collectoraction-bukrs AND
          kunnr = wa_collectoraction-kunnr AND
          dat   = wa_collectoraction-dat.

SORT lt_coll_act BY bukrs kunnr dat time DESCENDING.

LOOP AT it_collectoraction ASSIGNING <fs_collectoraction>.
" the READ TABLE finds the first matching row,
" it will be MAX(TIME) as TIME is sorted descending       
  READ TABLE lt_coll_act INTO ls_coll_act
      WITH KEY  bukrs = <fs_collectoraction>-bukrs
                kunnr = <fs_collectoraction>-kunnr
                dat   = <fs_collectoraction>-dat BINARY SEARCH.
  <fs_collectoraction> = ls_coll_act.
ENDLOOP.
3
votes

Instead of adding a selection query inside a loop, get all data into an internal table and handle it with read statements inside the loop.

Adding select queries inside a loop will always slow down the execution of an application as the application has to execute database queries for each loop. Loading all required information into an internal table and then handling data within the application is much more faster.

Let me know if you require any further details on this.

0
votes

First of all I want to thank all of you for your help. I change the logic of select by using an internal table with all records from dbtab according to the selection data of the user. So the code became as follow:

DATA: wa_collectoraction TYPE zcollectoraction,
  it_collectoraction TYPE TABLE OF zcollectoraction,
  itsort_collectoraction TYPE HASHED TABLE OF zcollectoraction
      WITH UNIQUE KEY mandt bukrs kunnr yearmonth dat time.

FIELD-SYMBOLS: <fs_collectoraction> LIKE LINE OF it_collectoraction.

SELECT bukrs kunnr yearmonth MAX( dat ) AS dat
  FROM zcollectoraction
    INTO CORRESPONDING FIELDS OF TABLE it_collectoraction
  WHERE bukrs IN so_bukrs AND
        kunnr IN so_kunnr AND
        dat   IN so_date
  GROUP BY bukrs kunnr yearmonth.

" Keep the total records which will be inserted.
i_tab_lines = sy-dbcnt.

SELECT * INTO TABLE itsort_collectoraction
  FROM zcollectoraction
  WHERE bukrs IN so_bukrs AND
      kunnr IN so_kunnr AND
      dat   IN so_date.

SORT itsort_collectoraction
            BY mandt bukrs kunnr yearmonth dat time DESCENDING.

LOOP AT it_collectoraction ASSIGNING <fs_collectoraction>.
  PERFORM progress_bar USING 'Retrieving data...'(035)
                             sy-tabix
                             i_tab_lines.

  READ TABLE itsort_collectoraction INTO wa_collectoraction
      WITH KEY bukrs = <fs_collectoraction>-bukrs
                kunnr = <fs_collectoraction>-kunnr
                yearmonth = <fs_collectoraction>-yearmonth
                dat   = <fs_collectoraction>-dat.
  <fs_collectoraction> = wa_collectoraction.
ENDLOOP.

This code run 43000 records in 1 minute. The only problem is that after the first 10000 to 15000 records the process is slowing down. I don't know if there is any command to clear sth. I don't know what to clear.

Again thanks a lot all of you. Regards Elias

PS. In the 1st 10 sec it process 14.000 records. In 1 minute process 38.500 and In 1 minute & 50 seconds finished the 54.500 records. It gives me the impression that it fulfills sth which slow-down the process. ANY IDEA?

-1
votes

I am a little late to the party, but what I see in your first post is that you just want to read the latest (max(date) and max(time)) entries from one table per bukrs and kunnr?

Use one select to get the table's content. Select only by keyfields or indexes: I assume that date is not a key field, but bukrs and kunnr:

SELECT bukrs kunnr yearmonth dat time
FROM zcollectoraction
  INTO CORRESPONDING FIELDS OF TABLE it_collectoraction
WHERE bukrs IN so_bukrs AND
      kunnr IN so_kunnr 
.

Delete non key fields from itab:

DELETE it_collectoraction WHERE dat NOT IN so_date.

Sort itab by date and time descending so that the latest entry is the first combination of bukrs and kunnr

SORT it_collectoraction BY bukrs kunnr date DESCENDING time DESCENDING.

Delete all adjacent (=all with same compare key after the first) entries per bukrs and kunnr

DELETE ADJACENT DUPLICATES FROM it_collectoraction COMPARING bukrs kunnr.