当前位置: 首页 > news >正文

043、表类型与表定义

043、表类型与表定义

昨天半夜被一个实习生拉去排障,程序逻辑看起来完全没问题,数据也没问题,就是把一条记录INSERT到内表的时候,运行时直接dump了。报错是ITAB_ILLEGAL_SORT_ORDER。我一看,这哥们用的内表是SORTED类型,往里面塞数据的时候,并没有按关键字顺序放入。他一脸无辜:“我循环里加了排序啊,怎么可能没排序?”我让他把定义贴出来,他写的是:

DATA: lt_itab TYPE SORTED TABLE OF mara WITH NON-UNIQUE KEY matnr.

这定义看着没问题吧?问题出在他循环里用INSERT往这个表里插数据时,数据来自两个不同的源,合并后乱了序。SORTED表要求你插入时键值已经有序,或者你直接APPEND,但APPEND在SORTED表上很容易出问题,因为你没法保证后加的键值比之前的大。实际上,SORTED表内部用的是二叉搜索树,你插入一个比根节点小的数据,树会自动调整,但ABAP运行时为了性能,做了个假设:你要是用APPEND,那必须保证键值单调递增。如果违反了这个假设,它不一定报错,但如果你用了INSERT,它会严格检查键的顺序,一旦发现前一条比后一条大,直接抛异常。

这事让我想起另一个坑:HASHED表。很多人以为HASHED表就是哈希索引,访问快,就什么都用它。但HASHED表最怕你用LOOPSORT。它本身是无序的,你没法按索引访问,更不能APPEND(因为哈希表根本不允许APPEND,只能用INSERT)。你要是想对它排序,对不起,你不能对HASHED表直接SORT,必须先COPY到STANDARD表里再排序。这不是性能问题,这是语义上不允许。

所以,回到“表类型”这四个字,在ABAP里其实有两层意思。一层是数据字典里的“表类型”(Table Type),它是描述内表结构的类型对象,属于DDIC里和域、数据元素、结构体并列的元数据类型。另一层是我们日常挂在嘴边的“内表类型”,就是STANDARD、SORTED、HASHED这三种。而这三种类型,在数据字典里又必须通过一个Table Type来定义,不然你没法在ABAP程序里直接引用一个字典表类型作为内表类型。这两者千万别搞混。

我见过不少从其他语言转过来的朋友,一开始被“表类型”这个名字唬住,以为是数据库表的结构定义。其实数据库表的定义在ABAP里叫“透明表”(Transparent Table),它对应物理上的数据库表,而Table Type是纯逻辑层的内表模板。你在SE11里创建的是Table Type,给别人用的时候,别人直接用TYPE table_type_name就能得到一个内表。透明表则要用TYPE STANDARD TABLE OF dbtab之类的方式去引用。这是两个完全不同的东西,甚至可以说一个管内存,一个管存储。

现在展开说下三种内表类型。STANDARD表是最普通的,它按插入顺序排列,可以用索引访问,也可以键访问。它的查找是线性扫描,数据量大时会慢,但ABAP也会用二分法查找——前提是你先SORT,并且用READ TABLE WITH KEY或者SORTED BY。注意,如果你没排序就去用BINARY SEARCH,那你得到的结果是未定义的,可能在调试时看起来对,但上线后偶发错乱。这不算踩坑,这算自爆。

SORTED表一旦声明了关键字,你插入的数据就得符合排序规则。它的好处是读取非常快,READ TABLE直接用键值二分查找,不需要先SORT。但它的写入代价高,而且容易触发上面说的dump。所以在SAP项目中,SORTED表通常只用来存配置数据、主数据这些静态内容。动态拼接的临时数据,千万别用SORTED。

HASHED表则是为等值查询优化的,键唯一性要求高,内部采用哈希码映射。它没有索引,不能做LOOP操作,也不能SORT。如果你需要大表快速取单条记录,并且键唯一,用HASHED很合适。但如果你要把多个表关联或者做嵌套循环,HASHED反而会因为不支持索引扫描而变慢,但它的READ TABLE速度是O(1),和SORTED表的O(log n)有本质区别。

实际开发中,我用STANDARD表占了九成。为什么?因为ABAP内表操作太灵活了,APPENDINSERTDELETEMODIFYSORTLOOP全部都能用。SORTED和HASHED只是特定场景的优化。不要为了炫技而用高级表,除非你明确知道性能瓶颈在哪。曾经有个项目,某个接口需要批量读取物料主数据,用了STANDARD表然后READ TABLE WITH KEY,在数据量上万以后明显卡顿。我把那个内表改成SORTED表,并且确保数据插入时按MATNR排序后,接口耗时从5秒降到0.3秒。这才是用SORTED表的正确姿势:读多写少,插入有序。

再讲一下数据字典里的Table Type定义。SE11创建Table Type时,有几个关键字段:行类型(Row Type)、访问方式(Access Type)、键定义(Key Definition)。访问方式就是STANDARD、SORTED、HASHED,还有RANGE(特殊类型,用于表示区间)。键定义可以指定非唯一或唯一。你把这个Table Type建好后,在程序里DATA: lt_itab TYPE zts_mytype.就直接得到一个内表。这个内表的类型和属性完全由字典控制,好处是同一个表类型可以被多个程序复用,改一处全生效。而且该类型还能作为函数方法接口的参数类型,跨程序传递内表时不用反复定义结构。我们项目里有个公共的ZTT_AMC_MSG,就专门用来传消息列表,所有接口都引用它,测试和排错都能统一处理。

但有个细节容易坑人:如果你在SE11里定义了一个SORTED表类型,但它允许非唯一的键,那么在ABAP里使用它时,如果插入相同键的数据,会排在后面,符合预期。但如果你定义成唯一键,却试图插入相同键,直接运行时错误。这比SORTED表的排序错误更隐蔽,因为很多人以为非唯一=可以重复,唯一=不能重复,但在SORTED表下,唯一键是依靠键值比较来保证的。敲代码时别只想着业务逻辑,务必先看表类型的键定义是UNIQUE还是NON-UNIQUE。

还有一种“表定义”聊法,是指创建透明表。透明表在SE11中定义,它包含字段、数据类型、长度、是否允许空值,以及搜索帮助、外键等。这个定义和Table Type不同,它最终会在数据库中生成一个物理存储表。ABAP程序里访问透明表,一般用OPEN SQL,比如SELECT * FROM ztable INTO TABLE @gt_data。透明表本身的定义直接决定了你的数据存储结构,所以字段类型选择上要谨慎。这里有个常见坑:数据库表字段类型如果是QUANCURR,需要同时定义参考表域中的单位字段,否则激活时可能报错;或者激活后数据精度有问题。定义表时还要注意,不要随便用CHAR类型做日期字段,要用DATS,否则排序大小和范围都可能出错。这些都是老生常谈,但每次项目里总有人犯。

还有,如果你在透明表定义时加了某个字段做索引,查询时能用到;但如果建了太多索引,写入就会变慢。索引不是越多越好。我的经验是:一个表最多三个索引,优先放在外键和常用过滤条件上。别为一个偶尔跑的报表建索引,那只会拖累日常业务。

写到这里,回到我那个实习生的问题。他最后怎么解决的?我让他把内表类型从SORTED改回STANDARD,然后如果需要按物料号快速读取,就用SORT BY matnr,再READ TABLE WITH KEY matnr = ... BINARY SEARCH。这样既不会dump,性能也够用。但他不甘心,问为什么不用SORTED表然后每次插入前排序?我说你插入前排序意味着你每来一条数据都要对现有表排序,那比维护一棵二叉搜索树还慢,而且还要处理数据来源顺序的不确定性。何必呢?内表类型选择是权衡,不是炫技。

最后说个实用的小建议。如果你在一个循环里往一个STANDARD表里插入数据,并且之后要按某个字段频繁读取,别急着APPEND,你可以先APPEND,等循环结束后再SORT,然后READ时加BINARY SEARCH。这是最经典、最不容易出错的组合。如果你确定数据本身有序,也想省那一次排序,那就直接声明SORTED表,但插入时一定要保证顺序,否则dump了别怪我没提醒。如果你要的是按主键查一条,并且主键唯一,那HASHED表是不错的选择,但你要不要再想着对它做SORTLOOP动态修改了——那不是它该干的事。

表类型和表定义,看起来只是ABAP里几个名词,但用不好就会在半夜收到runtime error短信。你是想半夜被叫醒,还是想安稳睡个觉?先从这几种类型的底层逻辑开始理解吧。

http://www.cnnetsun.cn/news/4142622.html

相关文章:

  • 终端完全指南:从核心概念到高效实践,解决常见问题
  • BETAFPV Configurator 实战:5 分钟跑通遥控器配置与固件刷写桌面工具
  • CEM系统厂商排名视角下:2026学年教育行业学员标签体系与360度画像构建及续报运营
  • ORB-SLAM3 加权误差 马氏距离
  • Book118 文档下载器:免费把网页预览转成 PDF
  • 免费身份证归属地查询 接口实测
  • 容器安全入门:K8s常见基础安全风险通俗解读
  • DeepAgents 通用智能体开发指南
  • SpaceX收购Cursor:AI编程工具进入生态整合新阶段,开发者如何应对?
  • LangMARL:当大语言模型学会团队协作,开启多智能体强化学习新范式
  • CustomThreads:让 Fusion 360 快速生成 3D打印螺纹配置,FDM 也能顺利旋合
  • QModMaster:免费 ModBus 主站调试工具,5 分钟跑通 RTU/TCP 完整路径
  • DDrawCompat:三步让 DirectX 老游戏在 Win11 跑起来
  • Python自动化视频处理:精准提取51秒片段与关键帧序列生成实战
  • 强化学习中的上下文压缩:让智能体学会抓重点,攻克长视野任务难题
  • RobotHelper:免Root安卓自动化框架完整入门指南
  • Android EDLA项目常用网站介绍
  • IPv6 Toolkit 完整指南:17 个命令工具搞定 IPv6 安全评估、地址扫描与故障排查
  • 文档切分算法详解
  • TMSpeech 免费离线语音转文字:完整指南,从装模型到实时字幕
  • 逍遥安卓模拟器(逍遥模拟器)
  • 可循环复用型定制重型纸箱在珠三角制造业的普及前景与落地难点
  • NLP问题--中文分词
  • Iwara4A:用“暴力自动重连“驯服无响应的 Iwara 服务器
  • 基于主从博弈的配电网-多微网双层优化模型Matlab实现与算法对比
  • 武汉工程大学《线性代数》期末试卷及答案2017-2023学年PDF
  • fanqienovel-downloader 完整上手指南:把整本番茄小说存到本地
  • Office 激活实操:许可证钩子原理与 5 分钟部署步骤
  • Tinke:免费NDS游戏ROM资源查看与编辑器,从0到首次解包
  • NVIDIA GPU驱动安装与故障排查全指南:从原理到实践