SAP technical topicObjectPerformance of nested CDS viewsModuleRAP_CDS_ODATA

Performance Cost of Nested CDS View Stacks

Nesting CDS views is not free. The ABAP CDS compiler tries to flatten a whole stack into one SQL statement, but constructs like AMDP table functions, currency conversion, UNION ALL, and calculated fields used in outer filters break that flattening. Each break becomes an optimization boundary: everything above it must wait for the layer below to fully materialize before filtering happens.

This page covers what actually happens to SQL generation when CDS views consume other CDS views several layers deep, and why a stack that runs fine in development can be catastrophic at production volume. It focuses on the specific constructs that stop the database optimizer from pushing filters down through the stack, and how to find and fix them before go-live rather than after.

Published 16 Sept 2026· 1,500 words

What it is

A nested CDS view stack is a chain where a consumption or projection view selects from a composite view, which itself selects from one or more basic views built on database tables. Each layer can add associations, calculated fields, unions, or filters. At activation and runtime the ABAP CDS compiler attempts to collapse the entire stack into a single SQL statement handed to the database, so that filtering and joins happen as close to the table as possible. The one structural fact that explains most confusion here: this collapsing only happens when every layer in the stack is pushdown-compatible. The moment one layer contains something the optimizer cannot push through, that layer becomes a materialization boundary. Everything below it runs first and in full; everything above it then operates on the already-materialized result set, with none of its filters reaching the underlying table. A stack that looks identical in the editor can behave completely differently in the generated SQL depending on what one layer, three levels down, happens to contain.

When to use it

Layering is the right tool when it enforces genuine reuse: a basic view is the single source of truth for a table, a composite view adds business logic used by several consumers, and a projection view exposes only what one service needs. This is standard RAP architecture and is meant to be nested two or three levels deep. It is the wrong tool when layers exist purely for folder tidiness with no actual reuse behind them, when an analytical aggregation view is stacked directly on top of a highly associative transactional view for convenience, or when a table function or AMDP is buried in the middle of a stack just because it was easier to write logic procedurally than in CDS expressions. In those cases the extra layer buys nothing architecturally and costs a materialization boundary at runtime.

How it fits the stack

Below the stack sit CDS view entities built directly on database tables, sometimes table functions backed by AMDP. Above the stack sit projection views exposed through a service definition and service binding, consumed by OData and Fiori Elements, or embedded in a RAP business object as the underlying entity. The nested stack occupies the space between raw table access and the exposed service, replacing what used to be hand-written joins in ABAP reports or views built directly on the database with a declarative, reusable layer. It does not replace the database optimizer; it feeds it. What it supersedes is the older pattern of one flat, monolithic view doing everything, in favour of basic, composite, and consumption views each with a defined responsibility, at the cost of needing to actively manage what happens to the generated SQL at each boundary.

A worked example

A basic view selects sales order item data directly from the line item table. A composite view consumes it, adds an association to the business partner master and a calculated net value field, and applies a currency conversion annotation to convert that value to a reporting currency. A projection view on top exposes a filtered subset for a Fiori list report, with a where clause on delivery status and an access control applied through DCL. Tracing the generated SQL for this stack shows the currency conversion forcing the composite layer to materialize before the projection layer's status filter can be evaluated, because the conversion function operates row by row and cannot be pushed below itself. The fix is to filter on delivery status inside the basic or composite view, before the conversion happens, rather than relying on the projection layer's where clause to do it after the fact. The same list report, same fields, same annotations, runs an order of magnitude slower with the filter left in the wrong layer, and nothing in the CDS editor warns about it.

How to choose

  • How many layers are actually earning reuse, versus how many exist for aesthetic separation. Every additional layer is a candidate optimization boundary, not a free abstraction.
  • Where filtering logic belongs: push filters as close to the base table as the business logic allows, before currency conversion, before AMDP calls, before UNION ALL, not in the topmost consumption view where it is easiest to write.
  • Whether a materialization boundary is genuinely unavoidable, such as an AMDP table function needed for logic CDS cannot express. If it is unavoidable, everything that needs to filter that data should filter it before feeding it into that layer, not after.
  • Whether an analytical aggregation is being stacked on top of a transactional association chain. If so, consider whether the aggregation should sit closer to the base tables instead of on top of several joins it did not need.
  • Whether the stack has actually been checked against a realistic data volume using an explain plan or SQL trace before go-live, rather than validated only against a development client with a few hundred rows.
  • Whether flattening two layers into one, sacrificing some reuse, is worth it for a query that runs on every list report page load versus a batch report run once a night.

Common pitfalls

  • A stack that returns instantly in the development system with a few hundred rows can force a full table materialization at one layer and time out at production volume; the editor and unit tests give no signal of this.
  • Currency or unit conversion functions embedded mid-stack evaluate per row rather than set-based, and any filter applied above that layer arrives too late to help the database.
  • An AMDP-based table function anywhere in the stack blocks pushdown for every layer above it; the database cannot push a filter into a procedure it does not understand.
  • UNION ALL inside a lower layer, consumed by an upper layer with its own filter, often materializes every branch of the union before the outer filter is applied, even when the filter would have eliminated most branches entirely.
  • Each layer with its own DCL access control adds an additional authorization join or subquery; stacking three views each with access controls compounds the check rather than deduplicating it.
  • A calculated field referenced in an outer where clause or group by forces the inner view to be fully evaluated first, because the database has nothing to push the filter into until the calculation exists.
  • Including associations for convenience, expecting lazy evaluation to skip them when unused, works in most cases but not reliably enough to gamble on for high-volume entities; unused associations should not be exposed on the projection layer at all.
  • Deep stacks make debugging expensive: a slow list report requires walking the SQL trace layer by layer to find which one stopped the optimizer, and nothing in the CDS source itself points at the boundary.

ECC, S/4HANA and clean core

Layering basic, composite, and consumption CDS views is the recommended, clean-core-compatible way to extend S/4HANA: custom logic lives in custom views that consume standard SAP-delivered views without modifying them. That guidance does not relax the performance discipline; a clean-core-compliant stack can still be a slow one if filters sit in the wrong layer. What is discouraged now is stacking views many layers deep purely as a design habit, or wrapping AMDP logic inside layers that are then reused by several unrelated consumers, each inheriting the same materialization cost. An upgrade can also change how much of a given stack the compiler manages to flatten, since SAP's own delivered views change between releases; a stack that ran flat before an upgrade can pick up a new optimization boundary from a changed SAP base view and needs retesting, not just functional regression testing.

Whose problem this is

The developer builds the stack and is responsible for checking the generated SQL, not just functional correctness. The architect owns the layering decision: how many levels, what goes in DCL versus behavior logic, where AMDP is permitted. Handover for any CDS entity feeding a high-traffic list report should include an explain plan or SQL trace captured at realistic volume, not just a passing unit test.

Related SAP objects

Reviewed pages this object connects to in the ERPClimb knowledge graph.

Source: ERPClimb — https://erpclimb.com/sap-technical-topics/performance-of-nested-cds-viewsERPClimb is an independent platform and is not affiliated with SAP SE. Reference pages are written and reviewed by SAP consultants for learning and troubleshooting.