7.3Bloom · AnNot started

Declarative, projected, joined

Reading depth

What you'll learn

Replace a SELECT SINGLE in a loop with FOR ALL ENTRIES, and ideally a single INNER JOIN or CDS view — one set-based read instead of N round trips.

  • Anti-pattern: SELECT SINGLE inside LOOP AT — one round trip per row.
  • Better: FOR ALL ENTRIES — one statement, but you merge and de-dup yourself.
  • Best: a single INNER JOIN, or a CDS view consumed by one SELECT.

The single most common performance fix in custom ABAP is collapsing per-row database access into one set-based read. The anti-pattern is a `SELECT SINGLE` inside a `LOOP AT`: for every order you fire a separate query for the customer name, so a thousand orders cost a thousand round trips. The optimizer never sees the whole problem, and the application server spends its time waiting on the network.

The first improvement is FOR ALL ENTRIES: collect the keys, issue one statement, and merge the result back in ABAP. This cuts a thousand round trips to one, but you still de-duplicate the driver, must guard the empty-driver case, and do the join logic yourself in ABAP. It is better, not best — a useful middle step when the join cannot yet be expressed declaratively.

The winning form is a single INNER JOIN — or, better still, a CDS view consumed by one SELECT. You name exactly the columns you need, the join happens on HANA where the data lives, and the optimizer can choose the plan. The same three columns that took a thousand queries now take one projected, joined statement. Internalize the progression — per-row SELECT SINGLE → FOR ALL ENTRIES → a single join or CDS — because you will apply it again and again.

Key points

  • Anti-pattern: SELECT SINGLE inside LOOP AT — one round trip per row.
  • Better: FOR ALL ENTRIES — one statement, but you merge and de-dup yourself.
  • Best: a single INNER JOIN, or a CDS view consumed by one SELECT.
  • Name the columns and let the join run on HANA where the data lives.
  • The progression per-row → FAE → join/CDS recurs constantly in custom code.

Examples

BeforePer-row SELECT SINGLE in a loop

One query per order to fetch the customer name — N round trips, no set-based optimization.

ABAPloop at lt_orders assigning field-symbol(<o>).
  select single name1 from kna1
    into @<o>-customer_name
    where kunnr = @<o>-customer_id.
endloop.
BeforeMiddle step — FOR ALL ENTRIES, then merge

One statement instead of N, but you still de-duplicate the driver, guard the empty case, and stitch the result back by hand.

ABAPselect kunnr, name1
  from kna1
  for all entries in @lt_orders
  where kunnr = @lt_orders-customer_id
  into table @data(lt_kna1).
" ... then loop and merge name1 into lt_orders
AfterBest — a single projected INNER JOIN

Named columns, the join executed on HANA, the optimizer free to choose the plan; one statement does it all (a CDS view would be cleaner still).

ABAPselect o~order_id, o~customer_id,
       k~name1 as customer_name, o~total
  from zorder_hdr as o
  inner join kna1 as k on k~kunnr = o~customer_id
  where o~status = 'OPEN'
  into table @data(lt_result).

Source notes: clean-core-curriculum §7.3

Ask Claude

Build a prompt from this lesson + your question and open a fresh Claude chat with it pre-filled — handy for adapting a before/after pattern to your own object.