Performance Tuning of ABAP report program – PART 1
Improving the performance of an ABAP report program
involves several programming techniques that optimize memory usage, reduce
processing time, and minimize database access. Here are some strategies to
improve performance:
1. Efficient
Database Access
Select only required fields: Always select
only the fields you need instead of using SELECT. This reduces the amount of
data transferred between the database and the application server.
abap
SELECT matnr, maktx FROM mara INTO TABLE
lt_mara WHERE matnr IN lt_matnr.
Use FOR ALL ENTRIES carefully: Ensure that the
internal table used in the FOR ALL ENTRIES clause is not empty to avoid
retrieving the entire dataset from the database.
abap
IF lt_matnr IS NOT INITIAL.
SELECT matnr, maktx FROM mara INTO TABLE
lt_mara FOR ALL ENTRIES IN lt_matnr WHERE matnr = lt_matnrmatnr.
ENDIF.
Avoid nested SELECT statements: Instead of
querying the database in a loop, use a single query to fetch the data.
Use JOIN instead of multiple SELECT: Combining
tables in a single query with a JOIN is more efficient than performing multiple
SELECT statements.
abap
SELECT a~matnr,
b~maktx FROM mara AS a
INNER JOIN makt AS
b ON a~matnr = b~matnr INTO TABLE lt_data.
2. Internal
Table Optimization
Choose the appropriate internal table type:
Use the right type of internal table based on the operations you need to
perform.
Standard Table: For simple data storage and
sequential processing.
Sorted Table: For tables that need to be
sorted by a key, providing faster access for binary searches.
Hashed Table: For large datasets requiring
fast key-based access (constant time complexity).
Use SORT and BINARY SEARCH: Sorting an
internal table and using BINARY SEARCH improves performance when searching
large tables.
abap
SORT lt_data BY matnr.
READ TABLE lt_data WITH KEY matnr =
lv_matnr BINARY SEARCH.
3. Minimize
Memory Consumption
Clear unnecessary data: Free up memory by
clearing or refreshing internal tables when they are no longer needed.
abap
CLEAR lt_data.
REFRESH lt_data.
Avoid deep structures when not necessary: Keep
data structures simple to avoid excessive memory consumption.
4. Use Parallel
Processing (RFC)
Distribute the workload across different
processors using parallel processing techniques like CALL FUNCTION with STARTING
NEW TASK. This allows long running reports to be processed faster.
abap
CALL FUNCTION 'YOUR_FUNCTION' STARTING NEW
TASK 'TASK1' PERFORMING task_finished ON END OF TASK.
5. Buffering
Leverage table buffering: For frequently
accessed static data, enable buffering at the dictionary level to reduce
database hits. This can be configured in the technical settings of the table.
Buffer reads: Instead of fetching the same
data from the database repeatedly, store the data in a buffer for reuse.
6. Optimize
Looping Structures
Minimize nested loops: Nested loops result in
exponential complexity and should be avoided wherever possible.
abap
LOOP AT lt_outer.
READ TABLE lt_inner WITH KEY key =
lt_outerkey.
ENDLOOP.
Instead, use a
single loop or optimize by using parallel processing or joins.
Use LOOP AT GROUP for grouping data: Instead
of using nested loops or manually grouping data, use the LOOP AT GROUP
statement to process data in groups efficiently.
abap
LOOP AT GROUP g_group OF lt_data INTO
DATA(group_data).
ENDLOOP.
7. Using Field
Symbols and Data References
Use field symbols: Accessing internal tables
via field symbols can be faster because it avoids copying data.
abap
LOOP AT lt_data ASSIGNING <fs_data>.
ENDLOOP.
Data references: Use references to pass large
data structures instead of copying them to save memory and processing time.
8. Effective
Use of Modularization
Avoid redundant code: Modularize your code
using subroutines, methods, and function modules to reduce redundancy, which
also aids performance optimization.
Minimize database access in loops: Move all
database access outside the loops, or fetch data once and store it in internal
tables for reuse.
9. Optimize ALV
Grid Reports
Use ALV with larger data: When dealing with
large datasets, the ALV grid (Object Oriented ALV) is more efficient for data
presentation compared to custom loops with WRITE.
10. Use
SELECTOPTIONS and RANGES
Instead of hardcoding values in the WHERE
clause, use SELECTOPTIONS and RANGES for dynamic selection, which allows for
faster processing and filtering of data.
11. Indexing
on Database Tables
Ensure that appropriate indexes exist on the
tables used in your program. This reduces the time for searching and retrieving
data.
12. Use CDS
Views for Complex Queries
In HANA environments, using Core Data Services
(CDS) views can offload complex data operations to the database level, taking
advantage of HANA’s in memory processing capabilities.
13. Efficient
Use of Aggregation Functions
Use aggregation functions (SUM, COUNT, AVG) in
the SQL query itself rather than fetching the entire dataset and performing the
calculations in ABAP.
By using these techniques, you can significantly improve
the performance of your ABAP report program. Each method addresses a specific
aspect of performance, from reducing database load to optimizing memory and
processing efficiency.
Here’s how to implement the various performance
improvement in ABAP code, along with explanations of each point:
1. Avoid
Nested SELECT Statements
Nested SELECT statements lead to multiple database
accesses and can be inefficient. It's better to perform a single SELECT with
joins or use internal tables for further processing.
Example:
abap
Inefficient
(Nested SELECT):
LOOP AT lt_orders
INTO wa_orders.
SELECT SINGLE FROM vbap INTO wa_vbap WHERE vbeln = wa_ordersvbeln.
ENDLOOP.
Optimized (Single
SELECT):
SELECT a~vbeln,
a~erdat, b~matnr, b~kwmeng
INTO TABLE lt_vbeln_data
FROM vbak AS a
INNER JOIN vbap AS b ON a~vbeln = b~vbeln
WHERE a~vbeln IN lt_orders.
Explanation: Instead of fetching each row in a loop with SELECT
SINGLE, join the tables in one query for better performance.
2. Use
INTO TABLE Instead of APPEND in SELECT Statements
Avoid appending records one by one in a loop. Use INTO
TABLE to retrieve all records at once.
Example:
abap
Inefficient (Using
APPEND):
SELECT FROM vbak INTO wa_vbak.
APPEND wa_vbak TO lt_vbak.
ENDSELECT.
Optimized (Using
INTO TABLE):
SELECT FROM vbak INTO TABLE lt_vbak.
Explanation: This retrieves all records in one go,
reducing the need for multiple accesses to the database.
3. Order of WHERE
Clause Based on Index
When a table has multiple indices, the WHERE clause
should align with the fields of the index, either primary or secondary.
Example:
abap
SELECT FROM mara
INTO TABLE lt_mara WHERE matnr = lv_matnr AND werks = lv_werks.
Explanation: If there’s an index for the fields matnr and
werks, ensure your WHERE clause follows the index sequence for faster database
lookup.
4. Use SELECT
UP TO 1 ROWS Instead of SELECT ... ENDSELECT ... EXIT
When testing for existence, use SELECT UP TO 1 ROWS
instead of looping through all the records with SELECT ... ENDSELECT.
Example:
abap
Inefficient (Using
SELECT...ENDSELECT):
SELECT FROM zflight INTO wa_flight WHERE airln = 'LF'
AND cntry = 'IN'.
EXIT.
ENDSELECT.
Optimized (Using UP TO 1 ROWS):
SELECT FROM zflight
INTO wa_flight WHERE airln = 'LF' AND cntry = 'IN' UP TO 1 ROWS.
Explanation: UP TO 1 ROWS stops the query as soon as it
finds one record, improving performance.
5. Use SELECT
SINGLE When Primary Key Fields Are Known
If all primary key fields are available in the WHERE
condition, use SELECT SINGLE.
Example:
abap
SELECT SINGLE FROM
mara INTO wa_mara WHERE matnr = lv_matnr.
Explanation: SELECT SINGLE is more efficient than
fetching multiple rows when you expect only one.
6. Column Updates
vs. Row Updates
To update multiple rows in a database, it is better to
use column updates in one query rather than updating each row individually.
Example:
abap
Inefficient
(Single row updates):
LOOP AT lt_data INTO
wa_data.
UPDATE mara SET maktx = wa_datamaktx WHERE
matnr = wa_datamatnr.
ENDLOOP.
Optimized (Column
updates):
UPDATE mara SET
maktx = wa_datamaktx WHERE matnr IN lt_data.
Explanation: The column update handles multiple records
in a single operation, which reduces database accesses.
7. Use Indexes for Frequently Accessed Data
Ensure indexes are used for frequently accessed data,
improving query performance.
Example:
abap
Efficient query
leveraging indexes:
SELECT FROM mara
INTO TABLE lt_mara WHERE matnr = lv_matnr.
Explanation: This ensures the query benefits from an
index if one exists on matnr.
8. Using
Buffered Tables
Using table buffering for frequently accessed tables
improves performance by reducing database access.
Example:
abap
Assuming table
ZCUSTOMERS is buffered:
SELECT FROM
zcustomers INTO TABLE lt_customers.
Explanation: Table buffering minimizes database access,
as the data is stored in the application server's memory.
9. Use
Aggregate Functions (e.g., MAX, MIN, SUM)
Instead of calculating aggregates in ABAP, use database
aggregate functions for efficiency.
Example:
abap
Inefficient
(Manual calculation):
MAXNO = 0.
SELECT FROM zflight INTO wa_flight WHERE airln = 'LF' AND cntry
= 'IN'.
CHECK wa_flightfligh
> MAXNO.
MAXNO = wa_flightfligh.
ENDSELECT.
Optimized (Using
Aggregate function):
SELECT MAX( fligh ) FROM zflight INTO MAXNO WHERE airln = 'LF'
AND cntry = 'IN'.
Explanation: The database can perform aggregate functions
like MAX or SUM much faster than ABAP can.
10. FOR
ALL ENTRIES in SELECT Statements
FOR ALL ENTRIES is used to fetch data based on multiple
entries in an internal table, but it should be used cautiously.
Example:
Abap
Inefficient (Nested SELECT):
LOOP AT lt_cntry
INTO wa_cntry.
SELECT SINGLE FROM zfligh INTO wa_fligh WHERE cntry =
wa_cntrycntry.
APPEND wa_fligh TO lt_fligh.
ENDLOOP.
Optimized (FOR ALL
ENTRIES):
SELECT FROM zfligh INTO TABLE lt_fligh FOR ALL
ENTRIES IN lt_cntry WHERE cntry = lt_cntrycntry.
Explanation: FOR ALL ENTRIES creates a single SELECT
statement for all matching entries in the internal table, making it much faster
than nested loops.
Key Considerations
When Using FOR ALL ENTRIES:
Ensure the
internal table is not empty: If the driver table (lt_cntry in this case) is
empty, the query retrieves all records from the database.
Remove duplicates
and sort the driver table: This reduces unnecessary database access and
improves performance.
Manage memory
efficiently: Use FREE or PACKAGE SIZE to handle large amounts of data and avoid
memory issues.
Summary of
Performance Tips:
Use aggregate
functions for computing max, min, sum, and average values.
Use FOR ALL
ENTRIES cautiously, ensuring the driver table has unique, sorted values.
Avoid unnecessary SELECT
statements in loops and use optimized queries like SELECT INTO TABLE.
Ensure indexes are
utilized for better query performance.
Use buffered
tables to reduce database access for frequently read tables.
By following these practices, you can ensure your ABAP
programs perform optimally, especially when working with large datasets and
frequent database interactions.
Using JOIN instead of multiple SELECT statements improves
performance significantly at the database level because it reduces the number
of database accesses and network roundtrips, leading to faster data retrieval.
When you use multiple SELECT statements, the program sends several requests to
the database, one for each table, and processes each result individually. In
contrast, a JOIN allows the database to fetch all the required data in a single
operation, reducing overhead and utilizing database optimization techniques.
Why JOIN is
Better:
1. Fewer Database Calls: Instead of multiple SELECT
statements, a JOIN fetches data from related tables in one call.
2. Optimized Execution Plans: Modern databases optimize JOIN
queries to efficiently retrieve data, using indexes and table relationships.
3. Reduced Data Transfer: A single JOIN retrieves the
needed records and sends them back to the application server in one go,
reducing network load.
4. Less ABAP Processing: With a JOIN, data processing
happens at the database level, which is faster than fetching the data into ABAP
and processing it there.
Example: Multiple SELECT
Statements vs. JOIN
Scenario:
You need to fetch customer details from two related
tables:
Table KNA1:
Contains general customer data (Customer number KUNNR, Name, City).
Table KNVV:
Contains salesspecific customer data (Customer number KUNNR, Sales area,
Payment terms).
1. Inefficient
Approach (Multiple SELECT Statements)
abap
DATA: lt_customers
TYPE TABLE OF kna1,
lt_sales_data TYPE TABLE OF knvv,
wa_kna1 TYPE kna1,
wa_knvv TYPE knvv.
Fetch data from KNA1
SELECT FROM kna1
INTO TABLE lt_customers WHERE land1 = 'DE'.
Loop through KNA1
data and fetch corresponding KNVV data
LOOP AT lt_customers
INTO wa_kna1.
SELECT SINGLE FROM knvv INTO wa_knvv WHERE kunnr = wa_kna1kunnr.
APPEND wa_knvv TO lt_sales_data.
ENDLOOP.
Drawbacks:
Multiple database hits: For each customer in KNA1,
the program performs a SELECT SINGLE on KNVV. If there are 1000 customers, this
means 1000 additional database calls.
Increased network traffic: The data must be
sent back and forth between the application and the database for each SELECT
SINGLE.
Inefficient processing: Each query must wait
for the previous one to finish, which creates delays.
2. Optimized
Approach (Using JOIN)
abap
DATA:
lt_customer_data TYPE TABLE OF kna1,
lt_combined_data TYPE TABLE OF kna1.
Fetch data from KNA1 and KNVV in a single join
SELECT a~kunnr,
a~name1, a~ort01, b~vkorg, b~vtweg, b~zterm
INTO TABLE lt_combined_data
FROM kna1 AS a
INNER JOIN knvv AS b ON a~kunnr = b~kunnr
WHERE a~land1 = 'DE'.
Advantages:
Single database hit: All required data is
fetched in one JOIN statement, eliminating the need for multiple database
calls.
Reduced network traffic: The entire result set
is transferred from the database to the application server in one operation.
Database level optimization: The database can
use indexes and optimization techniques to execute the JOIN query more
efficiently.
Faster execution: Since the database handles
the data retrieval in one go, the overall time to retrieve the data is reduced.
Performance
Benefits of JOIN:
Reduced Database
Load: With a JOIN, the database handles data retrieval in one operation,
reducing overhead and resource usage.
Optimized Query
Execution: The database engine can optimize JOIN operations more effectively
using available indexes, leading to faster retrieval.
Fewer Network
Trips: By using a single JOIN, all data is fetched in one step, minimizing the
network roundtrips between the application and the database.
Visualizing the
Difference:
Multiple SELECT
Statements:
1. Application sends SELECT for KNA1.
2. Database retrieves records from KNA1.
3. For each record in KNA1, the application sends a SELECT
SINGLE for KNVV.
4. The database performs 1,000 additional queries (one
for each customer).
5. The application waits for each query to finish before
continuing.
JOIN:
1. Application sends a single JOIN query.
2. Database retrieves data from both KNA1 and KNVV in one
step, applying optimizations.
3. All relevant data is sent back to the application in
one go.
Using JOIN eliminates multiple database calls and allows
the database to perform the complex task of combining data from multiple
tables.
The database
engine is better equipped to handle large datasets and can use indexing and
other optimizations to speed up queries.
Fewer network
calls and reduced ABAP level processing lead to faster program execution.
Thus, using JOIN instead of multiple SELECT statements
ensures better performance, reduced network traffic, and more efficient data
handling at the database level.