name: abap-performance-hana description: ABAP performance best practices for S/4HANA and HANA database systems.Use when writing or reviewing ABAP code on HANA-based systems.IMPORTANT: First use the SAP system info tool to check the system type — if the system is ECC or runs on a traditional database (Oracle, DB2, MSSQL), load the abap-performance-ecc skill instead. Covers code pushdown, CDS views, AMDP, advanced SQL, and HANA-optimized patterns. argument-hint: '[ABAP code to optimize on HANA]' user-invocable: true disable-model-invocation: false
ABAP Performance — S/4HANA / HANA Database
These rules apply to SAP S/4HANA systems or any ABAP system running on HANA DB.
Before using this skill: Call the SAP system info tool. If the system is ECC on a traditional DB, use the abap-performance-ecc skill instead.
Core philosophy on HANA: Push data-intensive operations to the database. HANA is a columnar in-memory DB optimized for set-based operations, aggregations, and complex SQL. Let it do the heavy lifting. Keep ABAP for business logic, authorization, and exception handling.
Code Pushdown — The #1 Rule
Move data-intensive operations to the database layer.
Push down to HANA:
- Aggregations (SUM, COUNT, AVG, MIN, MAX)
- Filtering (WHERE clauses — the more selective, the better)
- Sorting (ORDER BY)
- JOINs (HANA handles complex multi-table JOINs efficiently)
- String operations and arithmetic in SQL
- CASE expressions / conditional logic on data
- Grouping and HAVING
- Window functions (OVER/PARTITION BY)
- UNION / INTERSECT / EXCEPT
Keep in ABAP:
- Complex business logic with many branches
- Authority checks, messages, exceptions
- Small dataset processing where pushdown overhead exceeds benefit
- Operations requiring ABAP runtime features (RFC calls, file I/O, etc.)
Avoid:
- Reading all rows to ABAP and filtering/aggregating in loops
- Using internal tables as intermediate storage for what SQL can do in one statement
- Multiple sequential SELECTs that could be a single JOIN
Database Access
SELECT Patterns
-
Select only the fields you need. Never
SELECT *in production.SELECT matnr, maktx FROM mara INTO TABLE @DATA(itab). -
Always use a WHERE clause. Always use
@escaped host variables. -
Use JOINs aggressively — HANA handles complex JOINs very well, even 5+ tables.
SELECT m~matnr, t~maktx, p~werks, p~ekgrp FROM mara AS m INNER JOIN makt AS t ON t~matnr = m~matnr AND t~spras = @sy-langu INNER JOIN marc AS p ON p~matnr = m~matnr LEFT OUTER JOIN mvke AS s ON s~matnr = m~matnr WHERE m~mtart = @material_type INTO TABLE @DATA(materials). -
Use aggregate functions and GROUP BY — let HANA calculate:
SELECT werks, SUM( labst ) AS total_stock, COUNT(*) AS item_count FROM mard WHERE matnr = @matnr GROUP BY werks INTO TABLE @DATA(stock_by_plant). -
Use CASE expressions to push conditional logic to the DB:
SELECT matnr, CASE mtart WHEN 'FERT' THEN 'Finished' WHEN 'ROH' THEN 'Raw Material' ELSE 'Other' END AS type_text FROM mara INTO TABLE @DATA(materials). -
Use string functions in SQL:
SELECT matnr, CONCAT( matnr, CONCAT( ' - ', maktx ) ) AS display_text FROM mara INNER JOIN makt ON makt~matnr = mara~matnr AND makt~spras = @sy-langu INTO TABLE @DATA(display_data). -
Use
FOR ALL ENTRIESwhen JOINs aren't possible. Always check driver table is not empty. -
Use
UP TO n ROWSwhen you only need limited results. -
Use subqueries where they simplify logic:
SELECT matnr, maktx FROM mara WHERE matnr IN ( SELECT matnr FROM marc WHERE werks = @plant ) INTO TABLE @DATA(plant_materials).
CDS Views
- Prefer CDS views for complex data models. They are the primary code pushdown mechanism on HANA.
- CDS views are reusable, testable, and automatically optimized by HANA.
- Use CDS for: complex joins, calculated fields, aggregations, associations, access control.
- Consume CDS views in ABAP via
SELECT FROM zcds_view.
AMDP (ABAP-Managed Database Procedures)
- Use AMDP for very complex calculations that must run entirely on HANA.
- AMDP gives you access to full SQLScript (HANA's procedural SQL language).
- Use when: complex multi-step transformations, heavy string processing, graph operations, or when CDS is insufficient.
- AMDP is NOT portable to other DBs — use only when you're certain the system stays on HANA.
Avoiding Redundant DB Access
-
Never SELECT the same data twice. Read once, reuse.
-
Use
READ TABLEon internal table buffer instead ofSELECT SINGLEin a loop:SELECT matnr, maktx FROM makt WHERE spras = @sy-langu INTO TABLE @DATA(texts). " later: READ TABLE texts WITH KEY matnr = current_matnr INTO DATA(text_line). -
On HANA, even redundant DB access is faster than on traditional DBs — but it's still wasteful and adds network overhead.
Table Buffering
Buffering matters less on HANA than ECC because HANA is in-memory. But it still helps for:
-
Reducing network round-trips between app server and DB server
-
Avoiding query parsing overhead for tiny lookups
-
Use
SELECT SINGLEon buffered tables — reads from buffer.UP TO 1 ROWSbypasses buffer." good — uses buffer SELECT SINGLE * FROM t001 WHERE bukrs = @bukrs INTO @DATA(company). " bad — bypasses buffer SELECT * FROM t001 UP TO 1 ROWS WHERE bukrs = @bukrs INTO @DATA(company). -
JOINs, aggregates, GROUP BY, ORDER BY, subqueries bypass the buffer.
Internal Tables
Table Type Selection
Same rules as any ABAP system — this is ABAP runtime, not DB:
- HASHED: O(1) lookup. Large tables, unique key, read-heavy, filled once.
- SORTED: O(log n) lookup. Non-unique key, range access, incremental fill.
- STANDARD: O(n) unless sorted + binary search. Small tables or sequential.
" good — O(1) lookup
DATA materials TYPE HASHED TABLE OF mara WITH UNIQUE KEY matnr.
READ TABLE materials WITH TABLE KEY matnr = input INTO DATA(mat).
Loop Optimization
- Use
ASSIGNING FIELD-SYMBOL(<fs>)for fastest loop processing. - Use
WHEREon LOOP — especially on SORTED tables. - Avoid nested loops O(n*m). Use HASHED lookup for inner data.
- Use
FILTERfor extracting subsets from SORTED/HASHED tables:DATA(subset) = FILTER #( sorted_table WHERE status = 'A' ).
Bulk Operations
INSERT lines_offor bulk inserts.VALUE #( FOR ... )andREDUCEfor functional transformations.CORRESPONDING #( )for structure mapping.
HANA-Specific: Consider Pushing to SQL
Before writing a complex ABAP loop with aggregation, filtering, or transformation — ask: can this be a SQL statement instead?
" ABAP way (acceptable for small data)
LOOP AT sales ASSIGNING FIELD-SYMBOL(<s>).
AT NEW kunnr.
total = 0.
ENDAT.
total += <s>-netwr.
AT END OF kunnr.
APPEND VALUE #( kunnr = <s>-kunnr total = total ) TO totals.
ENDAT.
ENDLOOP.
" HANA way (better for large data)
SELECT kunnr, SUM( netwr ) AS total
FROM vbak
WHERE erdat >= @from_date
GROUP BY kunnr
INTO TABLE @DATA(totals).
String Operations
-
Use string templates
| |instead of CONCATENATE. -
Avoid repeated string concatenation in loops — build a string table:
DATA lines TYPE string_table. LOOP AT data INTO DATA(d). APPEND |{ d-field1 };{ d-field2 }| TO lines. ENDLOOP. DATA(csv) = concat_lines_of( table = lines sep = cl_abap_char_utilities=>cr_lf ). -
HANA-specific: For heavy string assembly from DB data, consider doing it in SQL with
CONCATorSTRING_AGG(via CDS/AMDP).
Authorization Checks
-
Check authority before expensive data retrieval:
AUTHORITY-CHECK OBJECT 'M_MATE_WRK' ID 'WERKS' FIELD plant. IF sy-subrc <> 0. RAISE EXCEPTION NEW zcx_no_auth( ). ENDIF. SELECT ... " now fetch -
On S/4HANA, consider CDS access control (DCL) for row-level authorization built into the data model.
ALV / UI Performance
- Pass data by reference.
- Use
CL_SALV_TABLEfor read-only display. - For very large result sets, consider pagination.
- On S/4HANA: consider Fiori/RAP for UI instead of classical ALV.
Parallel Processing
aRFCfor independent parallel tasks.SPTAframework for parallelized mass processing.- Background jobs for very long tasks.
- HANA-specific: Before parallelizing in ABAP, check if the work can be pushed to HANA — a single efficient SQL may outperform parallel ABAP tasks.
HANA Anti-Patterns
| Anti-Pattern | Fix |
|---|---|
SELECT * | Select only needed fields |
| SELECT in a LOOP | JOINs (HANA handles complex JOINs well) |
| Aggregating in ABAP loops | SUM/COUNT/AVG in SQL with GROUP BY |
| Filtering in ABAP what SQL can filter | Push WHERE to SQL |
| Multiple SELECTs that could be one JOIN | Combine into single JOIN statement |
| Nested LOOPs on STANDARD tables | HASHED lookup for inner data |
| Complex ABAP transformations on large data | CDS view or AMDP |
String concat in loops with && | Build string table, or push to SQL |
| Ignoring CDS views | Use CDS for reusable data models |
UP TO 1 ROWS on buffered table | SELECT SINGLE to use buffer |
| Authority check after data retrieval | Check before SELECT, or use CDS DCL |
| Writing ABAP for what SQL can express | Push to database — always ask "can SQL do this?" |