Performance Part 6: Internal Tables — Standard, Sorted and Hashed
Choose the right internal table type for performance: linear search on standard tables, binary search and sorted tables, hashed tables for key lookups, secondary keys, nested loops with WHERE on sorted tables, parallel cursor technique, and memory aspects.
Explanation
📌 KEY POINTS
✅ Standard table + READ TABLE WITH KEY = linear search: cost grows with table size; inside a loop it becomes quadratic.
✅ Sorted tables (or sorted standard + BINARY SEARCH) give logarithmic access; hashed tables give constant-time access by the full unique key.
✅ Nested LOOP … WHERE on a sorted inner table (key prefix) is optimised; on a standard table it scans the whole inner table every time.
⚠️ Nested loops over two large standard tables are the most common ABAP-side (CPU) performance problem after database issues.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Parts 4–5 moved data reads out of loops. Now the lookups inside those loops must be fast too.
━━━━━━━━━━━━━━━━━━━━
▶ 1. TABLE TYPES
- STANDARD: index access, fast APPEND; key search linear unless sorted + BINARY SEARCH.
- SORTED: always sorted by key (unique or non-unique); key and prefix searches binary; LOOP WHERE with key prefix optimised.
- HASHED: unique key only; READ with full key constant time; no index access.
━━━━━━━━━━━━━━━━━━━━
▶ 2. CHOOSING
- Lookup by full unique key (e.g. material master data) → HASHED.
- Range/prefix access or ordered processing, possibly non-unique (e.g. items per order) → SORTED.
- Mostly sequential processing/appending → STANDARD.
━━━━━━━━━━━━━━━━━━━━
▶ 3. NESTED LOOPS
- LOOP AT headers … LOOP AT items WHERE vbeln = header-vbeln: with items as SORTED by vbeln posnr → fast; as STANDARD → full scan per header.
- Parallel cursor (classic technique on sorted standard tables): READ first matching item with BINARY SEARCH, then LOOP FROM that index and EXIT when the key changes.
━━━━━━━━━━━━━━━━━━━━
▶ 4. SECONDARY KEYS
Tables can have secondary sorted/hashed keys for a second access path (7.02+); keep in mind maintenance cost when the table changes often.
━━━━━━━━━━━━━━━━━━━━
▶ 5. MEMORY
Large tables with wide lines consume memory; select only needed fields; free memory (FREE) of large tables no longer needed.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Run the code example with the inner table as STANDARD and as SORTED; compare with GET RUN TIME.
- Replace a READ on a standard table in a loop with a hashed lookup.
- Check with SAT that internal table operations dropped.
✅ CHECKPOINT: you pick table types by access pattern and avoid quadratic loops.
Code example
REPORT zperf_itab_types. TYPES: BEGIN OF ty_head, vbeln TYPE vbeln_va, END OF ty_head, BEGIN OF ty_item, vbeln TYPE vbeln_va, posnr TYPE posnr_va, netwr TYPE netwr_ap, END OF ty_item. DATA: lt_head TYPE STANDARD TABLE OF ty_head, ls_head TYPE ty_head, lt_item_st TYPE STANDARD TABLE OF ty_item, lt_item_so TYPE SORTED TABLE OF ty_item WITH UNIQUE KEY vbeln posnr, ls_item TYPE ty_item, lv_idx TYPE sy-tabix, lv_sum TYPE netwr. START-OF-SELECTION. SELECT vbeln FROM vbak INTO TABLE lt_head UP TO 5000 ROWS. IF lt_head IS NOT INITIAL. SELECT vbeln posnr netwr FROM vbap INTO TABLE lt_item_st FOR ALL ENTRIES IN lt_head WHERE vbeln = lt_head-vbeln. ENDIF. lt_item_so = lt_item_st. * ===== SLOW: nested loop on STANDARD table (full scan per header) =====* LOOP AT lt_head INTO ls_head.* LOOP AT lt_item_st INTO ls_item WHERE vbeln = ls_head-vbeln. ... ENDLOOP.* ENDLOOP. * ===== FAST: nested loop on SORTED table (key prefix) ===== LOOP AT lt_head INTO ls_head. LOOP AT lt_item_so INTO ls_item WHERE vbeln = ls_head-vbeln. lv_sum = lv_sum + ls_item-netwr. ENDLOOP. ENDLOOP. * ===== FAST (classic): parallel cursor on sorted STANDARD table ===== SORT lt_item_st BY vbeln posnr. LOOP AT lt_head INTO ls_head. READ TABLE lt_item_st TRANSPORTING NO FIELDS WITH KEY vbeln = ls_head-vbeln BINARY SEARCH. CHECK sy-subrc = 0. lv_idx = sy-tabix. LOOP AT lt_item_st INTO ls_item FROM lv_idx. IF ls_item-vbeln <> ls_head-vbeln. EXIT. ENDIF. " process item ENDLOOP. ENDLOOP. WRITE: / 'Total:', lv_sum.Real project scenario
A pricing simulation looped over 60,000 items and, for each, looped over a 200,000-line condition table with WHERE on a standard table. The CPU-bound job took 5 hours; STAD showed almost no DB time.
Changing the condition table to a sorted table with the lookup key as prefix reduced the inner loop cost dramatically; the job finished in 6 minutes with identical results.
Common mistakes
- READ/LOOP WHERE on large standard tables inside loops.
- BINARY SEARCH without matching sort.
- Hashed tables with partial key reads (full scan).
- Wide lines with unused fields.
- Not freeing large tables.
Best practices
- Hashed for unique full-key lookups.
- Sorted for prefix/range and nested loops.
- Parallel cursor for sorted standard tables.
- Select only needed fields.
- Measure with SAT.
Interview angle
Questions: "Standard vs sorted vs hashed?", "How do you optimise nested loops?", "What is the parallel cursor technique?"
Strong answer: standard linear search (binary if sorted), sorted log access and optimised LOOP WHERE on key prefix, hashed constant full-key access; nested loops: sorted inner table or parallel cursor (BINARY SEARCH then LOOP FROM index with EXIT on key change); secondary keys; memory considerations.
Practice this lesson
Quick check
1. Which table type gives constant-time lookups by full unique key?
2. Which internal table type is best for repeated exact unique-key lookup?
3. Which usually helps a WHERE clause on a large STANDARD internal table?
Interview questions
1. How do you optimise a LOOP AT itab WHERE ... on a large standard table?
Answer it in your own words first, then compare.
2. A large sales report repeatedly searches a standard internal table inside a loop. How do you optimise it?
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- Performance Part 1: Measuring with ST05, SAT and STAD
- Performance Part 10: Indexes, Selectivity and WHERE Conditions
- Performance Part 2: The Database-First Rule
- Performance Part 3: Tuning in Real Projects — Measure, Fix, Verify
- Performance Part 4: SELECT Inside LOOP — The Classic Performance Killer
- Performance Part 5: FOR ALL ENTRIES — Correct Use and Hidden Risks
- Performance Part 7: JOIN vs FOR ALL ENTRIES vs Nested SELECT
- Performance Part 8: HANA Pushdown with Open SQL, CDS and AMDP