Wednesday, 7 August 2013

Parallel Processing technique in SAP ABAP and its Advantages




For some SAP reports, the nights are getting too short. Especially at customers with large volumes of data, some SAP reports that customarily run in the background processing system (such as material planning runs) may have run times of many hours. It can be difficult to finish such jobs in the “night-time” that is available, especially if dialog users are spread across several time zones.

With Release 3.1G, SAP offers a solution to the “short nights” problem: parallel-processed background jobs. Long-running SAP reports can now implement parallel processing, which lets them parcel out the work to be done to available dialog work processes in the SAP system and then collect the results.

Parallel processing is implemented in ABAP reports and programs, not in the background processing system itself. That means that jobs are only processed in parallel if the report that runs in a job step is programmed for parallel processing. Such reports can also process in parallel if they are started interactively.

Important Note: Parallel-processing is implemented with a special variant of asynchonous RFC. It’s important that you use only the correct variant for your own parallel processing applications: the CALL FUNCTION STARTING NEW TASK DESTINATION IN GROUP keyword. Using other variants of asynchronous RFC circumvents the built-in safeguards in the correct keyword, and can bring your system to its knees


Below is the sample code which will guide us to implement Parallel Processing in future whenever needed.

*&---------------------------------------------------------------------*
*& Report  ZPAR_PARALLEL_PROCESS
*&
*&---------------------------------------------------------------------*

REPORT  zpar_parallel_process.

TABLES : mara.
DATA : bapimatdoa TYPE bapimatdoa,
       bapireturn TYPE bapireturn.
DATA : system TYPE rzlli_apcl,
       taskname(8) TYPE c,

index(3) TYPE c,
snd_jobs TYPE i,
rcv_jobs TYPE i,
exc_flag TYPE i,
mess TYPE c LENGTH 80.

TYPES : BEGIN OF type_material,
          desc TYPE maktx,
        END OF type_material.

DATA : material TYPE TABLE OF type_material WITH HEADER LINE,
       i_mara TYPE STANDARD TABLE OF mara.

DATA: functioncall1(1) TYPE c.
CONSTANTS: done(1) TYPE c VALUE 'X'.

FIELD-SYMBOLS: <fs_mara> TYPE mara.

SELECT-OPTIONS s_matnr FOR mara-matnr.

SELECT * FROM mara INTO TABLE i_mara WHERE matnr IN s_matnr.

**********************************************************************************
* RFC Server Group created from transaction RZ12
* It will be the config for Parallel processing.
* We can keep it as DEFAULT. In our case it is 'parallel_generators'
**********************************************************************************
system = 'parallel_generators'.

LOOP AT i_mara ASSIGNING <fs_mara>.
  index = sy-tabix.
  CONCATENATE 'Task' index INTO taskname. " Generate Unique Task Name

**********************************************************************************
* Below is the SYNTAX for calling our own FM (For which we need Papallel processing)
*
* CALL FUNCTION func STARTING NEW TASK task
*              [DESTINATION {dest|{IN GROUP {group|DEFAULT}}}]
*              parameter_list
*              [{PERFORMING subr}|{CALLING meth} ON END OF TASK].
*
* We can keep the syntax as DESTINATION IN GROUP DEFAULT instead of
*                           DESTINATION IN GROUP system
*
* The above syntaxes will creates Different task name TASK in a     separate work process.
* Each such task executes “process_parallel” in a separate work process.
*
**********************************************************************************
  CALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL' STARTING NEW TASK taskname
    DESTINATION IN GROUP system
    PERFORMING process_parallel ON END OF TASK
    EXPORTING
      material              = <fs_mara>-matnr
    EXCEPTIONS
      system_failure        = 1  MESSAGE mess
      communication_failure = 2  MESSAGE mess
      resource_failure      = 3.
  CASE sy-subrc.
    WHEN 0.
      snd_jobs = snd_jobs + 1.

    WHEN 1 OR 2.

      MESSAGE mess TYPE 'I'.
    WHEN 3.
      IF snd_jobs >= 1 AND
      exc_flag = 0.
        exc_flag = 1.

        WAIT UNTIL rcv_jobs >= snd_jobs

        UP TO 5 SECONDS.

      ENDIF.

      IF sy-subrc = 0.
        exc_flag = 0.

      ELSE.

        MESSAGE 'Resource failure' TYPE 'I'.

      ENDIF.

    WHEN OTHERS.

      MESSAGE 'Other error' TYPE 'I'.

  ENDCASE.
ENDLOOP.

WAIT UNTIL rcv_jobs >= snd_jobs.

LOOP AT material.
  WRITE : material-desc.
ENDLOOP.

*&---------------------------------------------------------------------*
*&      Form  process_parallel
*&---------------------------------------------------------------------*
* Each task will execute “process_parallel” in a separate work process.
*----------------------------------------------------------------------
FORM process_parallel USING taskname.

  rcv_jobs = rcv_jobs + 1.

  RECEIVE RESULTS FROM FUNCTION 'BAPI_MATERIAL_GET_DETAIL'
  IMPORTING
  material_general_data = bapimatdoa.
  bapireturn = bapireturn.
  functioncall1 = done.

  APPEND bapimatdoa-matl_desc TO material.
ENDFORM.                   





-----------------------------------------------------------------------
-----------------------------------------------------------------------

Program without Parallel Processing:

Here with normal loop process (without using parallel processing), the control would wait for each record inside the loop until the FM would return the values.

*&---------------------------------------------------------------------*
*& Report  ZPAR_LOOP
*&
*&---------------------------------------------------------------------
REPORT  ZPAR_LOOP.

TABLES : MARA.
DATA : BAPIMATDOA TYPE BAPIMATDOA,
       BAPIRETURN TYPE BAPIRETURN.

DATA: i_mara TYPE STANDARD TABLE OF mara.

FIELD-SYMBOLS: <fs_mara> TYPE mara.

SELECT-OPTIONS S_MATNR FOR MARA-MATNR.


SELECT * FROM mara INTO TABLE i_mara WHERE matnr IN s_matnr.

LOOP AT i_mara ASSIGNING <fs_mara>.
CALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL'
EXPORTING
MATERIAL = <fs_mara>-matnr
IMPORTING
MATERIAL_GENERAL_DATA = BAPIMATDOA.
write : BAPIMATDOA-MATL_DESC.
ENDLOOP.




With Parallel Processing (Runtime Analysis – SE30)
 











Without Parallel Processing (Runtime Analysis – SE30)












Now SAP has provided a standard framework for parallel processing. This is very sophisticated to use. Find the details in below link.


Tuesday, 6 August 2013

Parallel Cursor Vs. Nested Loop




Nested Loops – This is one of the fear factors for all the ABAP developers as this consumes lot of program execution time. If the number of entries in the internal tables is huge, then the situation would be too worse. The solution for this is to use parallel cursor method whenever there is a need for Nested Loop.
  
Sample program to compare the Parallel Cursor Vs. Nested Loop:


*&---------------------------------------------------------------------*
*& Report  ZPARALLEL_CURSOR_Vs_NESTED LOOP
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT  ZPARALLEL_CURSOR.

TYPES: ty_t_vbak TYPE STANDARD TABLE OF vbak.
DATA: it_vbak TYPE ty_t_vbak .
*
TYPES: ty_t_vbap TYPE STANDARD TABLE OF vbap.
DATA: it_vbap TYPE ty_t_vbap.
*
FIELD-SYMBOLS: <lfs_vbak> LIKE LINE OF it_vbak,
               <lfs_vbap> LIKE LINE OF it_vbap.
*
* necessary data selection
SELECT * FROM vbak
  INTO TABLE it_vbak
  UP TO 1000 ROWS.
CHECK it_vbak IS NOT INITIAL.
SELECT * FROM vbap
  INTO TABLE it_vbap
  FOR ALL ENTRIES IN it_vbak
  WHERE vbeln = it_vbak-vbeln.
*
DATA: lv_start_time TYPE timestampl,
      lv_end_time   TYPE timestampl,
      lv_diff       TYPE timestampl.
DATA: lv_tabix TYPE i.
*
*...... Normal Nested Loop .................................
* Get the Start Time
GET TIME STAMP FIELD lv_start_time.
*
* Nested Loop
LOOP AT it_vbak ASSIGNING <lfs_vbak>.
  LOOP AT it_vbap ASSIGNING <lfs_vbap>
                  WHERE vbeln = <lfs_vbak>-vbeln.
  ENDLOOP.
ENDLOOP.
*
* Get the end time
GET TIME STAMP FIELD lv_end_time.
*
* Actual time Spent:
lv_diff = lv_end_time - lv_start_time.
WRITE: /(50) 'Time Spent on Nested Loop', lv_diff.
*
CLEAR: lv_start_time, lv_end_time, lv_diff.
*
*....... Parallel Cursor with Nested Loop .......................
* Get the Start Time
GET TIME STAMP FIELD lv_start_time.
*
* Starting the Parallel Cursor
SORT: it_vbak BY vbeln,
      it_vbap BY vbeln.
LOOP AT it_vbak ASSIGNING <lfs_vbak>.
*
* Read the second internal table with BINARY SEARCH
  READ TABLE it_vbap TRANSPORTING NO FIELDS
       WITH KEY vbeln = <lfs_vbak>-vbeln
       BINARY SEARCH.
* Get the TABIX number
  lv_tabix = sy-tabix.
* Start the LOOP from the first accessed record in
* previous READ i.e. LV_TABIX
  LOOP AT it_vbap FROM lv_tabix ASSIGNING <lfs_vbap> .
*
*   End the LOOP, when there is no more record with similar key
    IF <lfs_vbap>-vbeln <> <lfs_vbak>-vbeln.
      EXIT.
    ENDIF.
*   Rest of the logic would go from here...
*
  ENDLOOP.
*
ENDLOOP.
*
* Get the end time
GET TIME STAMP FIELD lv_end_time.
*
* Actual time Spent:
lv_diff = lv_end_time - lv_start_time.
WRITE: /(50) 'Time Spend on Parallel Cursor Nested loops:', lv_diff.




Analysis report: Runtime in microseconds:  


Friday, 2 August 2013

Play with IDOC :-)



Transactions to play with IDOC(s):
RBDAPP01 - change status for Inbound IDOC (yellow to green)
RSEOUT00 - Process all selected IDocs (EDI)
RSNAST00 - trigger idoc with output type.
RBDMIDOC - trigger change pointer (BD21)
RBDAGAIN (For Outbound) - Process Outbound IDOCs with Error Again
RBDMANI2 (For Inbound) - Manual Processing of IDOCs: Post IDOCs Not Yet Posted
                                                (Reprocess the failed IDOC)
RBDAGAI2 - Reprocess IDOCs after inbound ALE Error (BD84)
RSARFCEX - Execute Calls Not Yet Executed
RBDMOIND - Status Conversion with Successful tRFC Execution
(to change the idoc status from 30 to 03)
RBDMANIN - Start error handling for non-posted IDocs
RBDSTATE - Send Audit Confirmations
BD87 - IDoc reprocessing
WE19 – IDoc reprocessing
Edit the iDoc using WE02 ……
Outbound:
RBDAGAIN or T-Code BD87
This would push your Idoc from *02*(Error passing data to port) to 30(Idoc ready to dispatch) status.
Now to send the Idoc from 30 to *03*(Data passed to port OK) use the "RSEOUT00" program and run another job as stated above.
This would send the Idocs to 03.
Similarly at Inbound side: 
To reprocess an Idoc in 51 status:
Use program "RBDMANI2" and run a job.It will push Idocs from 51 to 53 status.
For 64 status use "RBDAPP01" program.
You can do it in transaction code BD87

IDOC STATUS:
For Inbound --
53 - Idoc Posted successfully
51 - Failed .(Can find the reason under the status in WE02 or from Table - EDIDS).
68 - This is basically failure status .This happens in between between 64 and 51. (From here also we can find the cause of failure). Sometime what happened that there we can see that the green light against the IDOC but the latest status message is 68 (Error no further processing).
64 - Idoc ready for transfer. (We can use Transaction BD20 to process the waiting IDOCs).
50 - Idoc Added.
74 - Idoc was created by test transaction . (i.e-With using the transaction WE19).
For Outbound --
03 - Idoc passed to the port OK .
02 - Error passing data to port. (Could not find code page for receiving system).
30 - Idoc ready for dispatch.
01 - Idoc Generated .

Pop up for Month and Year

*&---------------------------------------------------------------------*
*& Report  ZPAR_TEST
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT  zpar_test.

DATA: v_year_month LIKE  isellist-month,
           v_code LIKE sy-subrc.


PARAMETER: v_month LIKE isellist-month.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR v_month.

  v_year_month = sy-datum+0(6).

  CALL FUNCTION 'POPUP_TO_SELECT_MONTH'
    EXPORTING
      actual_month               = v_year_month
      language                   = sy-langu
      start_column               = 8
      start_row                  = 5
    IMPORTING
      selected_month             = v_month
      return_code                = v_code
    EXCEPTIONS
      factory_calendar_not_found = 1
      holiday_calendar_not_found = 2
      month_not_found            = 3
      OTHERS                     = 4.