047 搜索帮助(Search Help)——从一次F4卡死说起
上周工厂的同事跑过来,说有个MIGO交货单收货界面,物料字段按F4没反应,转圈转半天,最后直接报“功能代码F4不存在”。我看了一眼,第一反应是“这怎么可能”,标准的MARA-MATNR自带的基本搜索帮助,怎么会在MIGO里死掉。然后上SAP拉ST22,发现短溢出堆栈里卡在一个自定义的搜索帮助退出函数里,再看代码,好家伙,里面写了个SELECT * FROM MARC,客户MARC几百万条,还套了个FOR ALL ENTRIES IN内表,内表还是空的。空表FOR ALL ENTRIES不会带条件,直接全表扫,不卡才怪。
这个坑让我想起搜索帮助这事,大家总觉得SE11里建个搜索帮助就和字典表一样简单,真出问题的时候,连个排查方向都没有。今天就把搜索帮助这块掰开揉碎,从最基本的概念到那些要命的细节,全过一遍。
先搞清楚搜索帮助在SAP里到底是个什么位置。你在屏幕字段上按F4,系统触发一个叫F4IF_INT_TABLE_VALUE_REQUEST或者F4IF_FIELD_VALUE_REQUEST的函数,然后根据屏幕字段的“搜索帮助路径”去找对应的搜索帮助。搜索帮助本身是个元数据对象,存在SE11里,它不存数据,只定义“我该去哪些表/视图查数据,返回哪些字段,显示哪些字段,怎么过滤”。真正干活的时候,搜索帮助会生成一个动态SELECT语句,跑一遍查询,然后把结果集送到F4对话框。
搜索帮助分两种,一种是基本搜索帮助,一种是集合搜索帮助。基本搜索帮助就是单打独斗,定义了一个数据源(表、视图、CDS),指定了“搜索帮助参数”的字段映射,比如“LIFNR对应LFA1-LIFNR,NAME1对应LFA1-NAME1”。集合搜索帮助是把几个基本搜索帮助打包,让用户在一个F4里切换不同的搜索方式,比如按供应商编号搜,按供应商名称搜,按国家/地区搜。这种“打包”不产生新的数据查询逻辑,它只是在F4界面上多个页签,每个页签对应一个基本搜索帮助。
建搜索帮助最常规的路径:SE11 -> 创建 -> 搜索帮助。选基本搜索帮助,进去后填一个简短描述,然后在“数据收集”选项卡里填数据源。数据源可以是表、数据库视图、投影视图、CDS视图。注意如果是表,必须是“可搜索的”,即存在索引或者至少主键字段独立。填完数据源,下面自动带出所有字段,你挑出需要的字段,给每个字段分配一个“搜索帮助参数名”,这个参数名是逻辑名称,不是物理字段名。系统会根据你这些参数名自动生成“IMP”和“EXP”标记,表示哪些是输入参数(传给搜索帮助的),哪些是输出参数(返回给屏幕的)。显示字段和光标定位字段也在这配置,但真正让用户看到哪些列,是“输出列表”里勾选的字段。
这里踩过一个坑:你在“搜索帮助参数”里的字段顺序决定了F4结果列表的列顺序,也决定了系统按什么顺序做文本匹配。比如你先把供应商名称NAME1放前面,把供应商编号LIFNR放后面,用户按F4后,默认光标落在名称上,输入“华东”就能过滤,而不是先输编号。这听起来挺方便,但很多顾问不知道,直接把LIFNR放在第一行,导致用户习惯性输名称时发现过滤无效,因为系统在编号字段上做“等于”或者“开头是”的匹配。配置搜索帮助时,字段顺序要按用户真正输入习惯来排,别按表结构顺序机械排。
接下来说搜索帮助出口(Search Help Exit)。这是高级功能,也是事故高发区。出口允许你在标准搜索帮助的四个阶段插入自己的ABAP逻辑:PRESEL(选择前)、SELECT(选择时)、DISP(显示后)、POV(值请求时)。最常见的写法是定义一个新函数,函数里通过CALL FUNCTION 'F4IF_SHLP_EXIT_EXAMPLE’来触发标准逻辑,或者完全自己写数据处理。很多团队喜欢在这里做权限校验、自定义数据源、临时加过滤条件,听起来很灵活,但稍微手抖就出事。
给一个典型出口函数框架,大家感受一下:
FUNCTION z_shlp_exit_custom. * 这个函数绑定在搜索帮助的“搜索帮助出口”字段上 * 注意函数必须包含一个名叫SHLP_TAB、CALLCONTROL、SHLP的结构参数 * 别自己乱定义,否则激活SAP会喷你 TABLES shlp_tab. CHANGING shlp TYPE shlp_descr. CHANGING calccontrol TYPE ddshfv4ctrl. CHANGING callcontrol TYPE ddshf4ctrl. ...看CALLCONTROL-CALLPHASE这个字段,它告诉你当前处在哪个阶段。'S’是SELECT,'D’是DISP,'P’是POV,'V’是PRESEL。你需要在每个阶段判断要不要执行自定义逻辑,执行完后把CALLCONTROL-STEP设置为0,表示继续标准处理,设置为1,表示跳过标准处理。我自己有一次调试同事写的出口,他在SELECT阶段直接把STEP设为1,然后自己调F4IF_INT_TABLE_VALUE_REQUEST弹了个内表,但是内表字段和搜索帮助的参数名对不上,结果屏幕字段收不到返回值,F4弹倒是弹了,用户选了行却带不回来。这种问题还不好查,因为断点进去每个变量都有值,就是回填失败。检查出口时重点看:内表字段名是否和SE11里“搜索帮助参数”的“LOW”字段名一致,返回时是否调用了F4IF_INT_TABLE_VALUE_REQUEST的“FIELD”参数,以及CALLCONTROL-STEP置1后是否遗漏了某些阶段的清理。
再回到开头那个MIGO卡死的案例。搜索帮助出口里写全表扫描会卡死,这个其实不算搜索帮助的错,是出口代码问题。但搜索帮助本身还有个隐藏的坑:如果搜索帮助数据源不是透明表,而是一个表连接视图,那么SAP在做文本搜索时可能不会走索引,尤其你输入“*”或者“%”开头的中缀通配符时。很多用户喜欢在F4里输入“ABC”来模糊搜索,这种需求在生产环境是灾难。标准F4默认支持“前缀搜索”,不支持“包含搜索”除非用户输入带%或者配置了搜索模式。别为了用户方便去改“搜索模式”为“中间匹配”,除非你的表是一张小配置表,否则几百万行的供应商主数据会让你数据库CPU直接飙红。
搜索帮助还有一类叫“集合搜索帮助”,之前说了是多个基本搜索帮助的“容器”。定义集合搜索帮助时,你要把几个基本搜索帮助加进去,然后给每个基本搜索帮助指定“搜索帮助参数”的映射关系。这里有个让人抓狂的机制:集合搜索帮助本身也有参数定义,当你调用某个屏幕字段的F4时,系统会根据屏幕字段的“搜索帮助路径”找到集合搜索帮助,然后把集合的参数传递给当前选中的那个基本搜索帮助。如果某个基本搜索帮助的参数在集合里没有对应,那个页签会直接报错“无参数定义”。我记得SAP标准TRESEARCH_HELP的集合搜索帮助,里面几个基本搜索帮助都共享同样的参数名,所以没问题。你自己建集合搜索帮助时,一定要确保每个基本搜索帮助用到的参数名都出现在集合参数列表里,哪怕只是同名传递。
屏幕字段绑定搜索帮助也容易出幺蛾子。你在SE11里给一个数据元素配置了搜索帮助,那么这个数据元素被所有屏幕字段引用时,F4都会触发它。但有时候你只想在某个屏幕上换成另一个搜索帮助,这时候不能改数据元素,要在屏幕属性里直接维护“搜索帮助”字段。对,就是ABAP屏幕的“属性”窗口里,有个F4帮助类型,可以设“仅显示”“内部表”“搜索帮助”“代码段”。如果你选了“搜索帮助”,下面填搜索帮助名。但这个搜索帮助名不能随便填集合搜索帮助?实际上可以填集合搜索帮助,只要它的参数能对应上屏幕字段的值。屏幕字段的值会作为“输入参数”传给搜索帮助,搜索结果回来时把“输出参数”对应字段回填到屏幕上其他字段。
这块有个非常隐蔽的问题:屏幕字段的“函数代码”如果被设置为包含“RESET”或者“FDOWN”之类的,F4可能被系统拦截。MIGO里物料字段F4没反应,原因之一就是屏幕里存在多个同名字段绑定,或者搜索帮助出口抛了个NOT_FOUND异常但没被捕获。所以在排查搜索帮助故障时,除了看ST22,还要打开ABAP调试器,在F4IF_START_VALUE_REQUEST里打断点,看传入的SHLP_NAME和FIELD_NAME对不对,看CALLCONTROL-STEP在出口里被改成什么。
我自己写搜索帮助的习惯是:能用基本搜索帮助解决的事,坚决不用出口;能用视图解决的数据源,坚决不用自定义表集合。因为搜索帮助的本质是“数据库查询的映射”,越简单越稳。真的遇到复杂权限过滤,优先考虑用DBSL或CDS加注解@Search.help的方式,CDS视图的搜索帮助支持在DDL里定义,还能配套权限隐式过滤,比出口性能强太多。SAP云环境里SE11传统的搜索帮助都已经不太用了,全部走CDS的@Search注解。但传统ABAP里,SE11搜索帮助仍然是主流,没办法。
最后说一个经验性的建议:如果你要给一个已经有线上数据的标准表添加搜索帮助,别用标准搜索帮助直接挂上去,先在开发环境造一堆测试数据,专门测F4的“全字段回车”“部分字段输入”“通配符输入”“无数据输入”这四种情况。全字段回车指的是用户按F4后不输入任何内容直接回车,系统会执行一次不带WHERE条件的全表SELECT。很多标准表这操作也能抗住,但如果你数据源是带连接视图或者有出口,极可能导致性能问题。必要的时候在出口里拦截空输入,或者用“最大结果数”限制返回行数。搜索帮助里有个“最大返回值”参数,默认500行,这个数字在自定义搜索帮助里可以调,但别调到999999,没人看得了那么多行,也伤数据库。
搜索帮助看起来不起眼,但用户日常操作每秒都在按F4。哪天你同事抱怨系统慢,打开ST05一抓,往往就是某个搜索帮助生成了个鬼SQL。这篇文章没提太多教科书概念,就希望你们遇到搜索帮助问题时,能想到这几个排查点:参数映射对不对、出口阶段有没有破坏STEP、集合搜索帮助参数有没有漏映射、数据类型有没有带出通配符、数据源索引能不能支撑无输入查询。记住了这些,至少不会再被F4卡死这种事搞到半夜。