ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ABAP on HANA实战:CDS View与AMDP联合开发指南

ABAP on HANA实战:CDS View与AMDP联合开发指南 1. SAP ABAP 开发者遇到的HANA时代焦虑这两年总有同事跑来问我项目要从ECC升级到S/4HANA我们这些写了十年ABAP的老家伙是不是就要失业了说实话我第一次听到“ABAP on HANA”这个概念的时候心里也是打鼓的。毕竟我们熟悉的报表开发、RFC调用、批处理程序在传统数据库上跑得挺好好的凭什么换了个数据库就要翻天覆地但真正接手了几个HANA迁移项目、把CDS View和AMDP用起来之后我发现自己之前完全是瞎焦虑。ABAP没死反而是变得更好玩了——当然也变得更需要动脑子了。这篇就把我这段时间把ABAP、CDS View、AMDP混在一起用的经验做个大梳理纯粹是个人实战记录不吹概念只讲实实在在怎么做、怎么避坑。先给刚接触这块的朋友划个重点ABAP on HANA不是一门新语言而是一套新的开发范式。你写的ABAP代码还在但能下推到数据库执行的部分要尽量下推以前那种把全表数据拉出来、在应用服务器上一行一行循环的做法在HANA时代就是慢性自杀。CDS View和AMDP就是把压力从应用服务器转移到数据库的两个主要武器。可能有朋友要问我是不是非学不可我的回答是如果你只想躺平维护老程序那你确实能混一阵子但新项目、新需求、新机会都会慢慢绕开你。反过来如果你愿意把这套东西吃透你会发现同样的业务需求以前要写几百行循环的报表现在几句CDS就搞定了那种感觉确实很爽。这篇文章适合谁三类人一是刚从ECC转S/4HANA、面对一堆性能优化建议不知所措的ABAP开发二是在校或培训机构学了传统ABAP、想往新方向走的初学者三是做技术选型、想评估HANA改造工作量的项目负责人。不管你属于哪一类这篇文章不聊虚的全部围绕标题里“大乱炖”这三个字讲清楚三样东西怎么配合、怎么落地。2. 吃透核心概念CDS View和AMDP到底解决了什么问题2.1 为什么传统ABAP在HANA上格外吃力先说个我踩过的真实案例。原先ECC时代有个库存报表逻辑不复杂取物料凭证、取采购订单、关联物料主数据三层嵌套循环最后输出一个列表。数据量大概百万级老数据库上跑四五十秒业务觉得能忍。迁移到HANA之后我以为会快很多结果一跑反而更糟糕——因为HANA是列式存储加并行计算我最擅长的那种“逐行处理逻辑”恰恰是它最不擅长的事情。问题出在哪儿传统ABAP的编程思维是面向过程的先把A表查出来放到内表循环这个内表再去查B表查完再循环关联C表。这种逐行访问的方式在HANA上会引发大量不必要的数据库访问而且应用服务器和数据库服务器之间的数据搬移量巨大。HANA再快也经不住你来回搬运几百万行数据。还有一个更隐蔽的坑S/4HANA启用了新的数据模型很多表结构跟ECC不一样了比如物料凭证变成了VBAK/VBAP这种抬头行项目拆分再加上新增的库存表MARC/ MARD语义变化如果你还是用旧SQL思维硬查连表都对不齐。2.2 CDS View用数据库的视角写业务逻辑CDS ViewCore Data Services简单理解就是在数据库层定义的一种可复用的数据模型。它不是简单的SQL视图而是能带参数、带关联、带计算字段、带权限控制的“高级数据模型”。最关键的是CDS View最终会由HANA数据库执行数据过滤、关联、聚合都在数据库内完成。这里要打个比方。以前我们做菜是把所有食材先搬到厨房台面上应用服务器再在台面上慢慢切、慢慢配而CDS View是直接在菜市场数据库里就把菜配好、切好、甚至半成品做好只把最终能直接下锅的食材拿回来。你说哪个效率高CDS View里面有几个东西我觉得一开始必须吃透关联Association不像传统JOIN要把关联关系写死Association是声明式的你可以把主表和关联表定义成导航路径用的时候直接路径访问。聚合与计算列Sum、Count、Min、Max这些可以直接在做View的时候算好写报表就不用自己在ABAP里累加了。参数化View可以定义输入参数调用的时候传值灵活性很高。权限控制通过DCLData Control Language做行级权限比在ABAP里硬编码权限判断强很多。2.3 AMDP把复杂的计算逻辑交给数据库存储过程AMDPABAP Managed Database Procedures是ABAP里定义的数据库存储过程但用ABAP代码关键字写成真正的执行体会被转换为HANA的SQLScript。简单说AMDP允许你在这里面写复杂的数据库逻辑同时又能被ABAP的调用环境统一管理。它不是用来替代CDS View的两者是互补关系。什么时候用AMDP我做下来的经验是当业务逻辑复杂到CDS View搞不定或者需要多步骤的临时结果集、条件分支、循环处理时上AMDP。比如复杂的财务分摊逻辑、多层BOM递归、按期间滚动计算库存结转这些用CDS很别扭但在AMDP里写SQLScript就相对顺手。有人会问我直接在HANA Studio里写存储过程不行吗当然行但那就是脱离了ABAP管理层——传输、版本管理、权限都要单独处理而且ABAP程序直接调用外部存储过程比较麻烦。AMDP的优势在于它长在ABAP对象里传输跟普通程序一样调试也还算友好。2.4 ABAP on HANA的整体技术栈关系我刚接触这块时最大的困惑就是这三样东西到底怎么排座次。后来我做了一个简化理解底层是HANA数据库负责存储和高效计算。中间层是CDS View主要负责数据建模、关联、聚合把基础数据模型定义好提供给上层用。执行层与算法层是AMDP处理CDS View表达不了的复杂逻辑或者需要性能敏感的自定义计算。顶层还是ABAP无论是Open SQL直接查CDS View还是调用AMDP方法最终的报表展示、ALV输出、RFC接口还是由ABAP包办。简而言之CDS View是用来“建模”的AMDP是用来“算”的ABAP是用来“控”的。三者各司其职叠加使用才能发挥最大威力。3. 环境准备与工具选型开发CDS View和AMDP需要什么条件3.1 等得起的后端系统版本先说硬性条件。CDS View的开发至少需要ABAP Application Server 7.4及以上版本AMDP则要求7.4 SP02或更高。你现在接触的项目大概率是S/4HANA 1909、2020甚至更高版本这些版本统统满足但如果你还在帮客户维护老系统的开发沙箱那就要确认一下版本号。有个细节CDS View在ABAP字典里有一个专门的开发对象类型DDLS你在SE11里是找不到“新建CDS View”按钮的必须用SE80或Eclipse里的ABAP Development Tools。所以老一套SE80开发习惯得改改了。3.2 Eclipse工具链ABAP Development Tools的配置很多老ABAPer一听到要在Eclipse里开发就皱眉但没办法CDS和AMDP这些新开发对象在SE80里功能太受限甚至根本无法完整开发。我在工作里标准搭配是Eclipse IDE for Java EE Developers或者官方发行版加ABAP Development Tools插件。JDK版本别用太老插件市场有要求JDK 11以上比较稳妥。装好后在Eclipse里配置ABAP项目连接输入系统连接信息、客户端、语言就可以像逛SE80一样浏览包和开发对象了。这里有个热词提一下很多人搜“eclipse安装jdk开发abap”说明卡在环境上的人不少。我建议别用最新的JDK 17或19部分插件兼容有坑JDK 11或JDK 8看插件版本最稳。3.3 权限与后台激活准备开发CDS View和AMDP需要新增一些开发权限对象比如S_ADT_RESADT资源权限、S_DEVELOP开发权限等。如果你是在标准客户环境里最好请BASIS同事开好角色不然在Eclipse里激活时会一脸懵。AMDP还需要在ABAP字典里创建对应的数据库过程因此还需要对HANA schema的权限。通常开发环境里会用开发用户但到了生产传输时需要确保变更传输的参数文件包含AMDP对象类型。这些细节我一开始都不知道后来被系统接连报错才补上的。4. CDS View从零写起一个能直接跑的示例4.1 需求定义用物料凭证统计采购收货数量为了不空谈我拿一个实际场景演示。假设业务要来这样一个报表统计每个工厂、每个供应商、每个月从采购订单收货的数量和金额支持按日期范围查询。看这个需求传统ABAP做法无非是先取EKPO采购订单行项目再取EKBE采购订单历史再关联MARA、LFA1等表最后内表汇总。数据一多就卡。现在用CDS View来做数据在数据库层就能关联、过滤、聚合。4.2 定义一个基础CDS ViewZCDS_PO_GR我先建一个核心视图负责最基础的关联和过滤。用DDLS写出来大概是这样AbapCatalog.sqlViewName: ZCDS_PO_GR_SQL AbapCatalog.compiler.compareFilter: true AccessControl.authorizationCheck: #CHECK EndUserText.label: 采购收货基础视图 define view ZCDS_PO_GR as select from ekbe as a association [1..1] to ekpo as b on b.ebeln a.ebeln and b.ebelp a.ebelp association [1..1] to mara as c on c.matnr a.matnr association [1..1] to lfa1 as d on d.lifnr a.lifnr { key a.ebeln, key a.ebelp, key a.buzei, a.budat as posting_date, a.menge as gr_qty, a.dmbtr as gr_amount, b.matnr, b.werks as plant, d.lifnr as vendor, d.name1 as vendor_name, c.mtart as material_type } where a.bwart 101这段代码做了什么首先我选了表EKBE采购凭证历史通过Association关联到EKPO和MARA、LFA1只取移动类型101采购收货的凭证。这样后续任何程序要查采购收货数据直接引用这个View就行了不用每次写一堆JOIN和条件。注意AbapCatalog.sqlViewName这定义了底层SQL视图名老的Open SQL程序也能用这个SQL视图名去查询兼容老代码这很重要。4.3 定义一个聚合CDS ViewZCDS_PO_GR_SUM基础视图做好后业务要看汇总数我不用接着写循环累加直接在CDS层面做聚合AbapCatalog.sqlViewName: ZCDS_PO_GR_SUM_SQL AccessControl.authorizationCheck: #CHECK EndUserText.label: 采购收货月度汇总 define view ZCDS_PO_GR_SUM as select from ZCDS_PO_GR { key plant, key vendor, date_format(posting_date, YYYYMM) as ym, sum(gr_qty) as total_qty, sum(gr_amount) as total_amount } group by plant, vendor, date_format(posting_date, YYYYMM)这里有几个字段级的细节date_format函数是HANA的SQL函数能直接把日期格式化成YYYYMM字符串用来做月份分组。sum()聚合直接输出汇总结果。有人说聚合视图不能带太多字段、会有性能问题。我实测在合适的索引和过滤条件下这种视图跑百万级数据完全没问题。关键是要用好过滤条件和下推。4.4 在ABAP里怎么查询CDS ViewCDS View定义好、激活后ABAP里就能用Open SQL直接查询。我最常用的写法SELECT plant, vendor, ym, total_qty, total_amount FROM zcds_po_gr_sum WHERE plant lv_plant AND ym BETWEEN lv_from AND lv_to INTO TABLE DATA(lt_result) UP TO 10000 ROWS.注意这里用的是zcds_po_gr_sum这是CDS View的实体名不再是SQL视图名。Open SQL直接能识别CDS实体。有一个坑如果你在Eclipse里改了View并激活但ABAP程序在SE38里还引用老字段可能编译报错。所以CDS字段变更一定要检查下游引用这个和改表结构一样需要评估影响。4.5 CDS View开发经验与避坑清单我总结一下这段时间写CDS View踩过的坑关联条件别乱加inner joinCDS里Association默认是Left Outer Join语义如果你业务上非要内连接要在条件里显式加上过滤否则数据量会变多。DCL权限千万别忽视如果View标注了authorizationCheck: #CHECK那运行时就会检查用户权限。第一次激活忘了建DCL对象调用时直接报无权限错误排查了半天。别把全部字段都给出来CDS View不是越多字段越好。字段越多数据库要处理的数据宽度越大能少取就少取。View套View要克制虽然CDS View支持基于View再建View但套太多层会导致执行计划复杂调试灾难。我一般控制在两层以内超过就考虑AMDP或直接改底层查询逻辑。5. AMDP实战当CDS View搞不定复杂逻辑时5.1 什么场景必须上AMDPCDS View适合“声明式”的数据建模定义好表和字段数据库自己负责优化。但有些逻辑是“过程式”的必须一步步算典型场景有这么几类递归/层级展开比如物料清单BOM多层展开CDS写不出来顺畅的递归查询。多步骤计算比如先算一个临时结果再拿临时结果跟另一个表做进一步处理中间过程需要落地到临时表。复杂变量和循环涉及游标式逐行处理、根据状态决定下一步动作CDS无能为力。大数据量的矩阵运算或分摊逻辑比财务分摊、成本流转等SQLScript写起来更贴近逻辑。5.2 AMDP类的骨架结构创建一个AMDP实际上是在ABAP类里定义一个特定的方法设置FOR AMDP关键字。一个最小示例如下CLASS zcl_amdp_gr_report DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_amdp_marker_hdb. CLASS-METHODS: get_gr_summary IMPORTING VALUE(iv_plant) TYPE werks VALUE(iv_date_from) TYPE budat VALUE(iv_date_to) TYPE budat EXPORTING VALUE(et_result) TYPE STANDARD TABLE OF zgr_summary_str. ENDCLASS. CLASS zcl_amdp_gr_report IMPLEMENTATION. METHOD get_gr_summary BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING zcds_po_gr. lt_gr SELECT plant, vendor, posting_date, gr_qty, gr_amount FROM zcds_po_gr WHERE plant :iv_plant AND posting_date BETWEEN :iv_date_from AND :iv_date_to; et_result SELECT plant, vendor, date_format(posting_date, YYYYMM) AS ym, SUM(gr_qty) AS total_qty, SUM(gr_amount) AS total_amount FROM :lt_gr GROUP BY plant, vendor, date_format(posting_date, YYYYMM); ENDMETHOD. ENDCLASS.这段代码里最关键的是类必须实现接口if_amdp_marker_hdb这是AMDP的“身份标识”。方法实现里用BY DATABASE PROCEDURE FOR HDB声明而不是普通ABAP代码块。USING子句列出这个AMDP会用到哪些表或CDS View必须写清楚数据库才知道权限和依赖关系。SQLScript里用:前缀引用参数和ABAP Open SQL的不一样千万别搞混。这个示例实际上做的事情和上文CDS聚合View差不多只是为了让你看清AMDP长什么样。真正的AMDP优势在更复杂场景我再展开一个多步骤处理的例子。5.3 多步骤AMDP示例滚动计算三个月平均收货金额业务需求计算每个工厂每个物料最近三个月的月度平均收货金额并且只在当月收货金额超过前三个月平均值的1.2倍时输出。这个逻辑涉及中间结果和时间窗口比较CDS直接写会很绕。AMDP里可以这样拆lt_monthly SELECT plant, matnr, date_format(posting_date, YYYYMM) AS ym, SUM(gr_amount) AS month_amount FROM zcds_po_gr WHERE posting_date BETWEEN :iv_from_date AND :iv_to_date GROUP BY plant, matnr, date_format(posting_date, YYYYMM); lt_avg SELECT plant, matnr, ym, month_amount, AVG(month_amount) OVER (PARTITION BY plant, matnr ORDER BY ym ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) AS prev_3m_avg FROM :lt_monthly; et_result SELECT plant, matnr, ym, month_amount, prev_3m_avg FROM :lt_avg WHERE month_amount prev_3m_avg * 1.2;你先算月度汇总然后用窗口函数AVG OVER计算前三个月的平均值最后过滤出超过阈值的数据。这套逻辑放在ABAP里用内表做光是排序和循环就够写半天在AMDP里几行SQLScript搞定而且全程数据没离开数据库。我第一次在项目里用窗口函数时感慨这就是HANA时代和传统时代的分水岭——你不需要在应用层维护状态、排序、临时变量数据库直接给你算好。5.4 AMDP常见报错与解决办法“Class does not implement if_amdp_marker_hdb”这个超常见。创建AMDP方法前必须先在类定义里加上INTERFACES if_amdp_marker_hdb少一步就报错。“Method ... is not a valid AMDP method”多半是因为方法没有用DESTINATION或缺少FOR AMDP声明。检查方法实现里的BY DATABASE PROCEDURE关键字。SQLSCRIPT编译报错查看方式在Eclipse里激活AMDP类时错误详情会显示为SQL Syntax错误。我遇到过因为参数名大小写不一致导致找不到变量的情况HANA的SQLScript对大小写是敏感的命名规范最好统一小写。性能不升反降如果AMDP里临时表结果太大又没有合理过滤可能占满内存。我通常在AMDP入口就确保有工厂、日期等强力过滤条件防止全表扫描。6. ABAP与CDS/AMDP如何和谐共处调用方式与代码组织6.1 Open SQL直接读CDS View的场景很多常规报表只需要简单过滤和汇总直接Open SQL查CDS View是最省事的。我建议这类查询就用Open SQL不需要特意包一层AMDP。代码简单、调试方便、模块化也好。举一个日常场景ALV报表要显示采购收货汇总数据源就是上文的ZCDS_PO_GR_SUM。ABAP里做了个选择屏幕用户输入工厂和日期ALV展示结果。这个场景完全不需要AMDPOpen SQL足够。6.2 调用AMDP方法获取复杂结果如果AMDP算完了结果要回传给ABAP继续处理比如再发邮件、再写日志、再拼ALV字段格式那就直接调用类方法DATA(lo_gr) NEW zcl_amdp_gr_report( ). DATA lt_result TYPE TABLE OF zgr_summary_str. lo_gr-get_gr_summary( EXPORTING iv_plant p_werks iv_date_from p_from iv_date_to p_to IMPORTING et_result lt_result ).需要注意AMDP方法的导出参数类型最好用字典结构或标准表类型不要全部用GENERIC否则调用时接口可能比对不上。我习惯在SE11里建好对应的结构或表类型这样方法签名清晰也方便后续复用。6.3 在AMDP里不能用哪些ABAP语法AMDP里写的是SQLScript不是ABAP所以好多ABAP习惯要戒掉不能用LOOP AT不要想着循环内表改用SELECT对临时表操作。不能用APPEND要往结果集加数据就是用SELECT、UNION、JOIN等方式组装。不能用WRITE TO、不能用CONCATENATE字符串拼接用||或CONCAT函数。变量声明用declare也可以在SELECT语句里直接生成列。注意字段类型转换ABAP的CURR、QUAN类型在SQLScript里可能涉及单位换算用的时候要确认。我第一次在AMDP里手滑写了个LOOP AT编译直接报错那会才意识到AMDP不是ABAP的替代品而是一种全新的SQLScript书写方式。6.4 性能测试减少数据传输量的收益有多大我给自己项目做过一次对比。同样一个复杂报表数据量约80万行传统ABAP写法内表循环关联耗时大约35秒应用服务器内存占用也高。用CDS View加Open SQL查询耗时降到8秒。用AMDP处理复杂分摊逻辑再返回结果总耗时控制在3秒左右。差距的核心不是某个函数神奇而是数据传输量完全不同。传统写法把几十万行原始数据拉到应用服务器中途还要反复和数据库交互CDS/AMDP则把大量计算留在数据库内只返回最终结果集。HANA的计算能力是它的强项应用服务器的优势在业务编排扬长避短性能自然就上来了。7. 排查技巧速查表CDS与AMDP的现场救火指南调试阶段我几乎每天都遇到各种奇怪问题。把最常见的几类整理成速查表方便直接对照。现象可能原因解决思路CDS View激活报语法错误字段名不存在或表改名S/4HANA废弃旧表检查当前系统表是否存在用SE11或数据字典确认必要时换用新表如从MARC换到相关HANA视图调用CDS View提示“无权限”缺少DCL对象或字段权限未配置为View创建DCL或临时将AccessControl.authorizationCheck改为#NOT_REQUIRED仅开发和测试环境生产不建议AMDP类激活失败报“Unknown identifier”SQLScript变量名或字段名大小写不一致检查SQLScript里参数名和字段名的拼写和大小写统一小写命名AMDP导入参数不能为空传入值为空导致SQLScript执行异常在ABAP调用前校验参数或者在AMDP内部加IF :iv_param IS NULL处理查询结果与ECC时期不一致S/4HANA数据模型变化、状态字段等表结构差异核对文档确认新逻辑、新状态字段例如库存表可能需要用VIMI类视图而非直接查MARCCDS聚合值重复翻倍Association一对多导致重复检查Association基数必要时先去重子查询再关联或改用EXISTS语义使用CDS View跨客户端查询报错CDS默认支持客户端自动追加但自定义扩展字段可能有问题检查自定义字段是否在对应表里维护客户端字段是否存在排查的大原则是先把SQLScript和视图的数据结果定位到数据库层再用DBSL TraceST05或HANA的PlanViz看实际执行计划和耗时不要一上来就怀疑ABAP代码。ST05跟踪里能看到Open SQL转成了什么底层SQL如果底层SQL里出现了意外的笛卡尔积那问题多半出在Association或CDS定义上。8. 大乱炖实践心得我推荐的分层开发套路说了这么多最后总结一下我个人在实际项目里的分层套路也当作给新手的落地指南。第一步先建模再写报表接到业务需求第一件事不是打开SE38写程序而是想想这个数据能不能先抽象成CDS View。基础表、关联关系、常用过滤条件都定义在CDS里。这样后面所有报表、接口、API都能复用这套数据模型口径也统一。第二步查询优先用Open SQL CDS View如果数据可以通过CDS View的过滤、关联、聚合直接得到就不要绕道AMDP。Open SQL简单、易调试、也容易做动态条件。第三步复杂计算交给AMDP一旦发现逻辑涉及多步骤、临时结果集、窗口函数、递归或者大量过程式计算果断上AMDP。宁可写一个专职的AMDP方法也不要在ABAP里堆循环。第四步应用层只做展示和交互ABAP传统技能依然重要比如ALV的事件处理、导出Excel、调用RFC、读写应用表等。但数据加工的重心要往数据库层下沉这样的代码在HANA上才能跑得快。再分享一个经验代码审查时多问一句“这个查询可不可以下推”。每次写普通ABAP报表前停两秒想想这个操作是不是非要在应用层做有没有可能在CDS里直接算这句话帮我避免了好多次性能事故。最后还有个心态建议CDS View和AMDP的学习曲线确实比传统ABAP陡一点尤其是如果你没接触过SQLScript和声明式建模。但别怕先用标准的CDS View做几个项目练手再慢慢尝试AMDP的窗口函数你会发现这些所谓的新技术底层还是数据库那套经典的东西——数据模型设计得好查询逻辑清晰怎么跑都快。ABAP on HANA不是要淘汰老ABAPer而是逼着我们换一种更聪明的写法。那些数据模型、性能优化、SQL和ABAP融合的能力反而是未来几年这个领域最吃香的本事。这套“大乱炖”你慢慢炖一定炖得出味道。
返回列表