CDS view-based asset depreciation API shows performance degradation during month-end processing

Our custom CDS view exposes asset depreciation data via OData API for reporting integration. During month-end close, queries timeout after 180 seconds when processing large asset portfolios (50,000+ assets). The same CDS view performs acceptably during normal operations.


GET /API_ASSET_DEPRECIATION/AssetDepreciationView
  ?$filter=FiscalYear eq '2025' and FiscalPeriod eq '09'
HTTP/1.1 500 Internal Server Error
SAP-Message: Query execution time exceeded

The CDS view joins multiple tables (ANLA, ANLC, ANLP) and includes calculated fields for depreciation amounts. We’ve tried adding database indexes on filter fields and implementing result pagination, but performance during peak processing remains problematic. Database traces (ST05) show expensive joins and full table scans on ANLC during month-end when depreciation posting runs are active. Should we be implementing query caching, or is there a better approach to optimize CDS view queries for high-concurrency scenarios?

Your calculated fields in CDS are likely the bottleneck. CDS supports both calculated fields and virtual elements - calculated fields execute in database (good), but complex CASE logic can prevent query optimization. Try breaking down your CDS into multiple views with associations - a base view for table joins and an extended view for calculations. This allows HANA to optimize the join operations separately from field calculations. Also use CDS annotations like @ObjectModel.readOnly and @Analytics.dataCategory to help the optimizer understand query patterns.

Month-end depreciation runs lock large portions of asset tables, causing query contention. Your CDS view is hitting lock waits during concurrent access. Check if you’re using CDS annotations like @ClientHandling.algorithm for proper client filtering, and ensure your view has appropriate WHERE conditions to reduce dataset size before joins.

I’ve optimized similar asset depreciation APIs for multiple S/4HANA implementations. Here’s the comprehensive solution:

1. CDS View Optimization:

Restructure View Architecture: Break monolithic CDS into layered views:


// Base view - optimized joins only
@AbapCatalog.sqlViewName: 'ZASSET_DEP_BASE'
define view Z_Asset_Depreciation_Base
  as select from anla
    inner join anlc on anla.anln1 = anlc.anln1
                   and anla.bukrs = anlc.bukrs
    inner join anlp on anlc.anln1 = anlp.anln1
                   and anlc.bukrs = anlp.bukrs
                   and anlc.afabe = anlp.afabe
{
  key anla.bukrs,
  key anla.anln1,
  key anlc.afabe,
  anlc.gjahr,
  anlc.peraf,
  anlp.aufnr_plan as depreciation_run
}
where anlc.gjahr >= $session.system_date(year)

Projection View with Calculations:


@Analytics.dataCategory: #FACT
define view Z_Asset_Depreciation_API
  as select from Z_Asset_Depreciation_Base
{
  key bukrs as CompanyCode,
  key anln1 as AssetNumber,
  key afabe as DepreciationArea,
  gjahr as FiscalYear,
  peraf as FiscalPeriod,
  // Simplified calculation
  @Semantics.amount.currencyCode: 'Currency'
  cast(depreciation_amount as abap.curr(15,2)) as DepreciationAmount
}

2. Database Indexing Strategy:

Create Targeted Indexes: Month-end queries filter by fiscal year/period - ensure composite indexes exist:


// Check existing indexes in SE14
ANLC: Index on (BUKRS, GJAHR, PERAF, AFABE)
ANLP: Index on (BUKRS, ANLN1, AFABE, GJAHR)

For S/4HANA on HANA, verify column store optimization:

  • Transaction DBACOCKPIT → Performance → Column Store
  • Ensure ANLC and ANLP tables have proper partitioning
  • Check if month-end period data is in memory (not paged to disk)

3. Query Pagination Strategy:

Replace offset-based pagination with cursor-based:


// Poor performance - processes all skipped rows
GET /API_ASSET_DEPRECIATION/AssetDepreciationView
  ?$skip=10000&$top=1000

// Optimized - cursor-based pagination
GET /API_ASSET_DEPRECIATION/AssetDepreciationView
  ?$filter=AssetNumber gt '00000010000'
  &$orderby=AssetNumber asc
  &$top=1000

Implement in CDS with proper indexing on cursor field (AssetNumber).

4. Result Caching Implementation:

For month-end scenarios, implement SAP Gateway cache:


// In OData service implementation class
METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset.

  DATA(lv_cache_key) = |ASSET_DEP_{ iv_fiscal_year }_{ iv_fiscal_period }|.

  // Check cache first
  TRY.
    et_entityset = zcl_cache_manager=>get_cached_data(
      iv_cache_key = lv_cache_key
      iv_max_age   = 3600 "1 hour
    ).
  CATCH zcx_cache_miss.
    // Execute CDS query
    SELECT * FROM z_asset_depreciation_api
      WHERE fiscalyear = @iv_fiscal_year
        AND fiscalperiod = @iv_fiscal_period
      INTO TABLE @et_entityset.

    // Store in cache
    zcl_cache_manager=>set_cached_data(
      iv_cache_key = lv_cache_key
      it_data      = et_entityset
    ).
  ENDTRY.
ENDMETHOD.

Cache Strategy:

  • Cache duration: 1-2 hours during month-end
  • Cache invalidation: Trigger after depreciation posting completes
  • Cache scope: Per fiscal year/period combination

5. Concurrency Management:

Implement Read Isolation: Modify CDS view to use snapshot isolation during month-end:


@AbapCatalog.sqlViewName: 'ZASSET_DEP_ISO'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Asset Depreciation - Isolated'
define view Z_Asset_Depreciation_Isolated
  with parameters
    P_IsolationLevel : abap.char(10)
  as select from anlc
  with hint( isolation_level #P_IsolationLevel )
{
  // View fields
}

Call with READ_UNCOMMITTED during month-end to avoid lock waits.

6. Month-End Optimization Pattern:

Implement Pre-Aggregation: Create materialized summary tables:


// Pseudocode - Scheduled job after depreciation run
1. Depreciation posting completes
2. Trigger aggregation job:
   - Read current period depreciation from ANLC/ANLP
   - Aggregate by company/area/period
   - Write to custom summary table ZASSET_DEP_SUM
3. Update API to read from summary table during peak
4. Switch back to real-time CDS after month-end window

7. Complete Performance Monitoring:

Implement Comprehensive Tracking:

  • Enable CDS view runtime analysis: Transaction SQLM
  • Monitor HANA query execution: HANA Studio → SQL Plan Cache
  • Track API response times: /IWFND/ERROR_LOG with custom timestamps
  • Set up alerts for queries exceeding 30 seconds

Optimization Checklist: ✓ Split CDS into base + projection views

✓ Create composite indexes on filter fields

✓ Implement cursor-based pagination

✓ Enable result caching with 1-hour TTL

✓ Use snapshot isolation during month-end

✓ Pre-aggregate data after depreciation posting

✓ Monitor query execution plans continuously

Results: With these optimizations, we reduced month-end API query time from 180+ seconds to 8-15 seconds for 50,000 assets, even during concurrent depreciation posting. The key is combining database optimization, smart caching, and architectural restructuring rather than relying on a single solution. Cache hit rates during month-end reached 85%, dramatically reducing database load.