Internal Tables Part 2: Choosing the Right Table Type
Pick STANDARD, SORTED or HASHED tables by access pattern: index access, key reads, range processing, uniqueness and data volume — with a decision table and measured examples.
Explanation
📌 KEY POINTS
✅ STANDARD: sequential processing, index access, small tables, or SORT + BINARY SEARCH.
✅ SORTED: frequent key reads, partial-key access and LOOP … WHERE on the leading key fields.
✅ HASHED: frequent reads by the full unique key on large tables (lookup tables).
⚠️ Table kind matters most for large tables and reads inside loops.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 1 introduced the three kinds. Now you learn to choose — one of the most important performance decisions in classic ABAP.
━━━━━━━━━━━━━━━━━━━━
▶ 1. HOW EACH KIND IS ACCESSED
- STANDARD: index access fast; READ … WITH KEY = linear search (reads row by row) unless you SORT and use BINARY SEARCH.
- SORTED: key access is a binary search (logarithmic); LOOP … WHERE on leading key fields is optimized; inserting keeps order (costly for many inserts in random order).
- HASHED: key access via hash — nearly constant time independent of size; only full unique key; no index, no ordering (SORT possible but rarely useful).
━━━━━━━━━━━━━━━━━━━━
▶ 2. DECISION TABLE
- Process every row once, in order → STANDARD.
- Build a table by APPEND and output it → STANDARD.
- Many reads by full unique key (e.g. material master lookup inside a loop) → HASHED.
- Many reads by partial key / ranges (all flights of a connection) → SORTED with NON-UNIQUE key.
- Need uniqueness enforced → SORTED/HASHED WITH UNIQUE KEY (duplicate insert fails / dumps on APPEND to sorted in wrong order).
━━━━━━━━━━━━━━━━━━━━
▶ 3. A TYPICAL CLASSIC PATTERN
Read header data (e.g. bookings) and a lookup table (flights). In the loop over bookings, read the flight for each booking. With 100,000 bookings and 50,000 flights:
- STANDARD + READ WITH KEY → up to 5 billion comparisons (minutes).
- HASHED + READ WITH TABLE KEY → 100,000 hash lookups (milliseconds).\n\n━━━━━━━━━━━━━━━━━━━━\n▶ 4. KEYS\n• Default key of standard tables (no explicit key) = all character-like fields — often wrong; define keys explicitly or use WITH EMPTY KEY for pure lists (7.40+).
- Sorted/hashed tables need a key definition.
- Secondary keys (Part 5) add extra access paths to any table.
━━━━━━━━━━━━━━━━━━━━
▶ 5. SIZE MATTERS
For a few dozen rows, the kind barely matters — choose for clarity. For thousands of rows accessed in loops, it decides runtime.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Run the code example: it measures reading 20,000 flights with a standard table vs a hashed table (GET RUN TIME).
- Compare the runtimes.
- Change the access to a partial key and use a sorted table.
💡 Modern syntax (7.40+): table expressions itab[ key = value ] work with all kinds; line_exists( ) for existence checks.
✅ CHECKPOINT: you choose the table kind by access pattern and can prove it with a measurement.
Code example
REPORT zitab_choose. TYPES: BEGIN OF ty_flight, carrid TYPE s_carr_id, connid TYPE s_conn_id, fldate TYPE s_date, price TYPE s_price, END OF ty_flight. DATA: gt_standard TYPE STANDARD TABLE OF ty_flight, gt_hashed TYPE HASHED TABLE OF ty_flight WITH UNIQUE KEY carrid connid fldate, gt_sorted TYPE SORTED TABLE OF ty_flight WITH NON-UNIQUE KEY carrid connid, gt_bookings TYPE STANDARD TABLE OF sbook, gs_flight TYPE ty_flight, gs_booking TYPE sbook, gv_t1 TYPE i, gv_t2 TYPE i, gv_std TYPE i, gv_hash TYPE i. START-OF-SELECTION. SELECT carrid connid fldate price FROM sflight INTO TABLE gt_standard. gt_hashed = gt_standard. " same data, different kind gt_sorted = gt_standard. SELECT * FROM sbook INTO TABLE gt_bookings UP TO 20000 ROWS. * ===== STANDARD + READ WITH KEY: linear search per booking ===== GET RUN TIME FIELD gv_t1. LOOP AT gt_bookings INTO gs_booking. READ TABLE gt_standard INTO gs_flight WITH KEY carrid = gs_booking-carrid connid = gs_booking-connid fldate = gs_booking-fldate. ENDLOOP. GET RUN TIME FIELD gv_t2. gv_std = gv_t2 - gv_t1. * ===== HASHED + READ WITH TABLE KEY: hash lookup per booking ===== GET RUN TIME FIELD gv_t1. LOOP AT gt_bookings INTO gs_booking. READ TABLE gt_hashed INTO gs_flight WITH TABLE KEY carrid = gs_booking-carrid connid = gs_booking-connid fldate = gs_booking-fldate. ENDLOOP. GET RUN TIME FIELD gv_t2. gv_hash = gv_t2 - gv_t1. WRITE: / 'Standard (linear) microseconds:', gv_std. WRITE: / 'Hashed microseconds :', gv_hash. * ===== SORTED: all flights of one connection (partial key) ===== LOOP AT gt_sorted INTO gs_flight WHERE carrid = 'LH' AND connid = '0400'. WRITE: / gs_flight-fldate, gs_flight-price. " optimized key range ENDLOOP.Real project scenario
A billing report looped over 200,000 invoice items and read the customer master from a standard internal table with READ … WITH KEY for each item. Runtime grew from minutes to over an hour as the customer base grew.
Changing the customer table to a HASHED table with a unique key and using READ … WITH TABLE KEY reduced the lookup part from 58 minutes to under a second. No other code changed. The team added "table kind for lookup tables" to their performance review checklist.
Common mistakes
- Standard tables with READ WITH KEY inside large loops.
- Hashed tables when index access or ordering is needed.
- Relying on the default key of standard tables.
- Sorted tables filled in random order with many inserts.
- Choosing a kind without measuring for large volumes.
Best practices
- Decide by access pattern: sequential, full-key lookup, partial-key ranges.
- Use HASHED for lookup tables read by full unique key.
- Use SORTED for partial-key access and LOOP WHERE.
- Define keys explicitly.
- Measure with GET RUN TIME or SAT for large volumes.
Interview angle
Questions: "When do you use a hashed table?", "Why is READ WITH KEY on a standard table slow?", "When is a sorted table better?"
Strong answer: standard tables for sequential processing and index access; READ WITH KEY on them is a linear search, so large lookups inside loops are slow; hashed tables give constant-time access by the full unique key — ideal for lookup tables; sorted tables use binary search and optimize partial-key access and LOOP WHERE on leading key fields. Measure for large data.
Practice this lesson
Quick check
1. A large lookup table is always read with its complete unique key. Which table type fits best?
2. Which internal table type gives the fastest read by primary key?
3. Which access is invalid on a HASHED table?
Interview questions
1. How would you decide between using a standard internal table with SORT + BINARY SEARCH versus declaring the table directly as a SORTED or HASHED table type, from a design and maintainability perspective?
Answer it in your own words first, then compare.
2. A pricing lookup table of 80,000 rows is read by condition key for every item. Which table type do you choose and why?
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
- Internal Tables Part 1: Standard, Sorted and Hashed Tables
- Internal Tables Part 10: Memory Management and Large Internal Tables
- Internal Tables Part 3: Work Area vs Field Symbol vs Data Reference
- Internal Tables Part 4: READ TABLE, sy-subrc and Table Expressions
- Internal Tables Part 5: SORT, BINARY SEARCH and Secondary Keys
- Internal Tables Part 6: APPEND, INSERT, MODIFY, DELETE and COLLECT
- Internal Tables Part 7: Removing Duplicates and Building Unique Datasets
- Internal Tables Part 8: LOOP Patterns — WHERE, Control Levels and Totals