使用排序表和散列表
学习目标
处理排序表和散列表。
试用:代码示例准备
选择 Ctrl + Shift + N 创建新的 ABAP 资源库对象。
在过滤器字段中键入单词 database ,标记搜索结果 数据库表 ,然后选择 继续 。
将新对象分配到正在使用的包并输入名称 ZS4D401_FLIGHTS 。输入表的描述,然后选择 下一步 。
将对象分配到传输请求并选择 完成 。
在大括号之间输入以下代码:
key client : abap.clnt not null;
key carrier_id : /dmo/carrier_id not null;
key connection_id : /dmo/connection_id not null;
key flight_date : /dmo/flight_date not null;
@Semantics.amount.currencyCode : 'zs4d401_flights.currency_code'
price : /dmo/flight_price;
currency_code : /dmo/currency_code;
plane_type_id : /dmo/plane_type_id;
seats_max : /dmo/plane_seats_max;
seats_occupied : /dmo/plane_seats_occupied;
选择 Ctrl + F3 激活表。
创建名为 ZCL_FILL_ZS4D401_FLIGHTS 的新 ABAP 类。
在 main 方法的实施中输入以下代码:
DATA flights TYPE TABLE OF /dmo/flight.
DATA insert_tab TYPE TABLE OF /dmo/flight.
DELETE FROM ZS4D401_flights.
SELECT FROM /dmo/flight FIELDS * ORDER BY carrier_Id, connection_id INTO TABLE @flights .
LOOP AT flights INTO DATA(first_date).
* Original table flights has 2 flights per connection. Only process the first
IF sy-tabix MOD 2 = 0. CONTINUE. ENDIF.
*Extend flight dates by 2000 days
DO 2000 TIMES.
APPEND first_date TO insert_tab.
first_date-flight_date += 1.
ENDDO.
* ENDIF.
ENDLOOP.
* Read highest connection number for each flight
SELECT FROM /dmo/flight AS main FIELDS carrier_Id, connection_id, flight_date, price, currency_code, plane_type_id
WHERE connection_id = ( SELECT MAX( connection_id ) FROM /dmo/flight WHERE carrier_id = main~carrier_id )
AND flight_Date = ( SELECT MIN( flight_date ) FROM /dmo/flight WHERE carrier_id = main~carrier_id AND connection_id = main~connection_id )
GROUP BY carrier_id, connection_Id, flight_date, price, currency_code, plane_type_id
ORDER BY carrier_id, connection_id
INTO TABLE @DATA(max).
*Add 50 new connection numbers and 2000 days of flights for each
LOOP AT max INTO DATA(line).
DO 50 TIMES.
line-connection_id += 1.
line-plane_type_id = SWITCH #( CONV i( line-connection_id ) MOD 2 WHEN 0 THEN 'A330' WHEN 1 THEN 'A350' ).
first_date = CORRESPONDING #( line ).
DATA(repetitions) = COND i( WHEN line-carrier_id = 'LH' AND line-connection_id = '0405' THEN 4000 ELSE 2000 ).
DO repetitions TIMES.
first_date-seats_max = 220.
APPEND first_date TO insert_tab.
first_date-flight_date += 1.
ENDDO.
ENDDO.
ENDLOOP.
SORT insert_tab BY carrier_Id connection_id flight_date.
DELETE ADJACENT DUPLICATES FROM insert_tab COMPARING carrier_id connection_id flight_date.
INSERT ZS4D401_flights FROM TABLE @insert_tab.
out->write( |Generated { sy-dbcnt } rows in table ZS4D401_flights| ).
选择 Ctrl + F3 激活类。
选择 F9 以运行类。 main 方法将在接下来的两个部分中填充代码片段所需的额外数据库表。
排序表和散列表
到目前为止,我们已使用标准内部表。标准表中的数据不按特定排序顺序保存。因此,当您从表中读取数据时,系统必须按顺序搜索表,直到找到您需要的行。根据表的大小,这可能需要一些时间。
可以使用排序表或散列表优化内部表的读取访问性能。

在排序表中,表的内容始终根据关键字段按升序排序。向表中插入新记录时,系统会确保将其放置在正确的位置。由于数据始终进行排序,因此系统可以比从标准表中更有效地检索记录(只要您遵循特定规则)。
哈希表使用特殊的哈希算法进行管理。这可确保即使表非常大,系统也可以非常快速地检索记录。但是,这种性能提升仅在非常特殊的情况下有效。
访问排序表
在本视频中,您将了解如何访问排序表。
视频:本节含 SAP 官方视频(视频 ID
1_8nwlfj07),需在 learning.sap.com 在线观看。

声明散列表时,必须使用唯一键定义它 – 不允许重复。
观看视频,了解如何访问散列表。
视频:本节含 SAP 官方视频(视频 ID
1_uw3pasov),需在 learning.sap.com 在线观看。
何时使用标准表、排序表和散列表

如果填充内部表并随后对整个表实施循环,则可以使用标准表。排序表和散列表的性能优化无关紧要,因为循环中没有过滤器。

此示例显示何时应使用排序表和散列表。它包含使用 where 子句中的第一个关键字段的表连接循环。这是使用排序表的情况,因为即使未完全指定键值,系统也可以使用二进制搜索技术。
程序在循环中查找表 航空公司 中的条目。因此,使用完整键值对表进行重复访问。这是使用散列表的理想情况。
标准表、排序表和散列表的比较运行时
此图比较了标准表、排序表和散列表的运行时。

填充排序表和散列表
使用标准表时,可以使用 APPEND 语句将工作区的内容添加到表的末尾。这不适用于散列表,并会导致语法错误。
从技术上讲,可以使用 APPEND 语句填充排序表。但是,如果根据排序顺序,您尝试附加的行不属于表末尾,则可能会造成运行时错误。在我们的示例中,会发生这种情况。

填充散列表和安全填充排序表的方法是使用 INSERT 语句。INSERT 确保在表中的正确位置插入新行。
试用:排序和散列表
创建实施接口 IF_OO_ADT_CLASSRUN 的新类。
将以下代码片段复制到方法 if_oo_adt_classrun~main() 的实施部分:
* Run this class using the ABAP Profiler to measure relative access times for standard, sorted, and hashed tables
data(flights) = new lcl_flights( ).
flights->access_standard( ).
flights->access_sorted( ).
flights->access_hashed( ).
out->write( |Done| ).
切换到 局部类型 标签并将以下代码片段复制到编辑器中:
CLASS lcl_flights DEFINITION.
PUBLIC SECTION.
METHODS constructor.
METHODS access_standard.
METHODS access_sorted.
METHODS access_hashed.
PRIVATE SECTION.
DATA standard_table TYPE STANDARD TABLE OF zs4d401_flights WITH NON-UNIQUE KEY carrier_id connection_id flight_date.
DATA sorted_table TYPE SORTED TABLE OF zs4d401_flights WITH NON-UNIQUE KEY carrier_id connection_id flight_date.
DATA hashed_table TYPE HASHED TABLE OF zs4d401_flights WITH UNIQUE KEY carrier_id connection_id flight_date.
DATA key_carrier_id TYPE /dmo/carrier_id.
DATA key_connection_id TYPE /dmo/connection_id.
DATA key_date TYPE /dmo/flight_date.
METHODS set_line_to_read.
ENDCLASS.
CLASS lcl_flights IMPLEMENTATION.
METHOD access_hashed.
DATA(result) = hashed_table[ carrier_Id = me->key_carrier_id connection_Id = me->key_connection_id flight_date = me->key_date ].
ENDMETHOD.
METHOD access_sorted.
DATA(result) = sorted_table[ carrier_Id = me->key_carrier_id connection_Id = me->key_connection_id flight_date = me->key_date ].
ENDMETHOD.
METHOD constructor.
SELECT FROM zs4d401_flights FIELDS * INTO TABLE @standard_table.
SELECT FROM zs4d401_flights FIELDS * INTO TABLE @sorted_table.
SELECT FROM zs4d401_flights FIELDS * INTO TABLE @hashed_table.
set_line_to_read( ).
ENDMETHOD.
METHOD access_standard.
DATA(result) = standard_table[ carrier_Id = me->key_carrier_id connection_Id = me->key_connection_id flight_date = me->key_date ].
ENDMETHOD.
METHOD set_line_to_read.
DATA(line) = standard_table[ CONV i( lines( standard_table ) * '0.65' ) ].
me->key_carrier_id = line-carrier_Id.
me->key_connection_Id = line-connection_id.
me->key_date = line-flight_date.
ENDMETHOD.
ENDCLASS.
选择 Ctrl + F3 激活类。
右键单击编辑器,然后选择 参数文件作为... → ABAP 应用程序(控制台) 。
在详细信息 中,取消选中复选框 SQL 数据库访问 并选择 完成 。
切换到 ABAP 分析器 透视图并双击跟踪项目(可能需要先刷新显示)。
选择 Hit List 。
比较方法 access_standard( ) 、 access_sorted( ) 和 access_hashed( ) 的运行时。
使用排序表和散列表
您发现代码包含表类型为 标准表 的大型内部表。在代码中分析访问这些表的方式,发现它们只能通过键访问。为提高性能,将内部表的定义更改为排序表或哈希表,具体取决于其访问方式。
模板:
/LRN/CL_S4D401_ITS_FSYM(全局类)
解决方案:
/LRN/CL_S4D401_ITS_TABLE_KIND(全局类)
任务 1: 复制模板(可选)
复制模板类 /LRN/CL_S4D401_ITS_FSYM。如果已完成上一练习,则可以跳过此任务并继续编辑类 ZCL_##_SOLUTION。
步骤
将类
/LRN/CL_S4D401_ITS_FSYM复制到您自己的包中的类(建议名称:ZCL_##_SOLUTION,其中 ## 代表组编号)。在项目浏览器中,右键单击类
/LRN/CL_S4D401_ITS_FSYM以打开上下文菜单。从上下文菜单中,选择复制....
在包字段中输入包的名称。在名称字段中,输入
ZCL_##_SOLUTION,其中 ## 代表组编号。选择下一步。
确认传输请求并选择完成。
激活复制。
按
Ctrl + F3激活类。
任务 2: 调整 CONNECTIONS_BUFFER
使用本地类 LCL_PASSENGER_FLIGHT 的静态属性 **connections_buffer**的使用位置列表。更改 connections_buffer 的定义,以便最适合其访问方式。
步骤
导航到本地类
LCL_PASSENGER_FLIGHT中静态属性connections_buffer的定义。例如,在 大纲 视图中展开
LCL_PASSENGER_FLIGHT节点并选择 CONNECTIONS_BUFFER 。为
connections_buffer属性创建使用位置列表。在 CLASS-DATA 语句中,右键单击
connections_buffer并选择获取调用清单。或者,您可以将光标放在connections_buffer上并按Ctrl + Shift + G。在编辑器下方的搜索视图中分析列表。将光标置于查找结果上以显示完整的语句。
调整
connections_buffer属性的定义。选择最适合读取访问的表类型和键值定义。将表类型更改为
HASHED TABLE。将键值定义更改为以
carrier_id和connection_id作为键值字段的唯一键值。如下调整代码:
* CLASS-DATA connections_buffer TYPE TABLE OF st_connections_buffer.
CLASS-DATA connections_buffer
TYPE HASHED TABLE OF st_connections_buffer
WITH UNIQUE KEY carrier_id connection_id.
任务 3: 调整 FLIGHTS_BUFFER
使用本地类 LCL_PASSENGER_FLIGHT 的静态属性 **flights_buffer**的使用位置列表。更改 flights_buffer 的定义,以便最适合访问 属性的方式。
步骤
导航到本地类
LCL_PASSENGER_FLIGHT中静态属性flights_buffer的定义。例如,展开概要视图中的节点
LCL_PASSENGER_FLIGHT,然后选择 FLIGHTS_BUFFER。为
flights_buffer属性创建使用位置清单。在 CLASS-DATA 语句中,右键单击
flights_buffer并选择获取调用清单。或者,您可以将光标放在flights_buffer上并按Ctrl + Shift + G。在编辑器下方的搜索视图中分析列表。将光标置于查找结果上以显示完整的语句。
调整属性
flights_buffer的定义。选择最适合读取访问的表类型和键值定义。将表类型更改为
SORTED TABLE。将键定义更改为以
carrier_id、connection_id和flight_date作为键字段的非唯一键。如下调整代码:
* CLASS-DATA: flights_buffer TYPE TABLE OF st_flights_buffer.
CLASS-DATA: flights_buffer
TYPE SORTED TABLE OF st_flights_buffer
WITH NON-UNIQUE KEY carrier_id connection_id flight_date.
在 问题 视图中分析语法错误。
分析编辑器下方的 问题 视图。
移除或注释冗余 SORT 语句。
如下调整代码:
* SORT flights_buffer BY carrier_id connection_id flight_date.
以控制台应用形式激活并测试全局类。
按
Ctrl + F3。按
F9。
任务 4: 量化改进
使用 ABAP 概要分析量化通过调整两个内部表的类型实现的性能改进。
步骤
在项目浏览器中找到模板类
/LRN/CL_S4D401_ITS_FSYM。将模板类
/LRN/CL_S4D401_ITS_FSYM作为 ABAP 控制台应用进行剖析。右键单击项目浏览器中的模板类
/LRN/CL_S4D401_ITS_FSYM,然后选择参数文件作为→ABAP 应用程序(控制台)。选择完成。
等待控制台视图出现或更新。
返回到您自己的类(
ZCL_##_SOLUTION,其中 ## 是您的组编号)并以相同方式对其进行剖析。在项目浏览器中找到您自己的类。
右键单击项目浏览器中的类,然后选择参数文件为→ABAP 应用程序(控制台)。
等待控制台视图出现或更新。
切换到 ABAP 概要分析 透视图并比较两个 ABAP 跟踪。
要打开 ABAP 概要分析透视图,请选择 窗口→透视图→打开透视图→其他....从 eclipse 菜单。然后选择 ABAP 概要分析并打开。(或者,如果可用,您可以选择 eclipse 工具栏右上角的 ABAP 概要分析 图标。)
在底部的 ABAP 跟踪视图中,展开与 ABAP 云项目相对应的节点。
按
F5键刷新跟踪结果清单。前两个跟踪结果应像您自己的 ABAP 类和模板类一样命名。比较运行时 (s) 列中的值。
分析后,返回到 ABAP 透视图。
像以前一样切换透视图。