Code Pushdown ってなんのことだろう?
2023-08-13:続編があります。こっちのほうがより実践的かもしれない。
ABAP New open SQL:Code Pushdown って何のこと?(2) - コントロールを取り戻せ!
ABAP New open SQL:Code Pushdown って何のこと?(3) - コントロールを取り戻せ!
2023-08-13:比較記事を書きました。(ABAP)CDS View vs HANA(Information)View
ABAP CDS View vs HANA Information View(HANA View):メモリ使用量比較|基幹システムのクラウド移行・構築・導入支援のBeeX
- 先日、SAP HANAの勉強会に参加したときのこと。
- 多少時代遅れ感はありますが、「ABAP CDS View vs HANA Infomation View」のスライドがありまして、ざっくり体感的には、HANA Infomation Viewが3倍から30倍くらい高速に動作します。
- 一時期、営業的なのかどうか不明ですが、SAPJ様が「ABAP CDS Viewのほうが速い」と発信していたらしいですが、実測してみると、HANA Infomation Viewの圧勝で、SAP HANAの仕組みを少し考えると、当然ということに気づきます。
- ただし、1千万~10億レコードといったボリュームの大きなデータを扱うときの話で、プロジェクトでアドオンプログラム(10万レコード程度)のパフォーマンスが出なくて困っていることとリンクしていないことが、なかなか伝わらないようでした。
- アドオンプログラムの場合、Netweaverのメモリ容量制限から、扱えるのは500万レコード位でしょうか?桁が違う話なのです。
- パフォーマンスが正義みたいな考え方はあまり好きでは無いのですが、R/3時代のルールで作成した(ITAB多用)プログラムも含めて乱暴な比較をすると以下のような感じになると思います。
(数値が大きい方が高速動作)
昔々SAP社様が、「東京→大阪を数秒で行ける」といった宣伝をしていました。
「ITAB多用で、2時間30分→9,000秒、,1,000倍高速なHANA Infomation Viewで置き換えに成功したとすると、9秒」
条件付きではありますが、嘘は言っていなかったと思います。
でも、これが90秒でもおそらく万々歳だと思うのです。そして、New Open SQLのみで実現できるとしたら...嬉しいですよね。
一方で営業的には、
「リアルタイム経営の為には、ビックデータの高速分析が必要です。Code Pushdownという設計手法があり、CDS Viewを採用することで実現します。」
「CDS→Pushdown→リアルタイム経営」みたいな。
多少逆説的ですが、ABAPコードの中の「LOOP文を、廃止または削減」すると、Code Pushdownが実現できると思います。そして処理速度100倍も夢ではないと思います。っということでプログラムを作ってみました。
外見上の振る舞いは変えずに5種類の実装方法を作りました。
処理としては、トランザクションを格納したテーブルから、会社コードのバリエーション一覧を取得します。
A-1
従来方式です。
ACDOCAのデータを取得して
SORT命令で並び替えて(Non-Pushdown)
DELETE命令で重複を削除する(Non-Pushdown)
A-2
従来方式の変形です。
ACDOCAのデータをORDER BY句で並び替えて取得して(Pushdown)
DELETE命令で重複を削除する(Non-Pushdown)
B-1
ACDOCAのデータをDISTINCT句で重複削除して(Pushdown)
ORDER BY句で並び替えて取得する(Pushdown)
B-2
ACDOCAのデータをGROUP BY句で重複削除して(Pushdown)
ORDER BY句で並び替えて取得する(Pushdown)
C-1
番外編
ACDOCAのデータを取得して
LOOP + BINARY SEARCHで、重複削除および並び替えする(Non-Pushdown)
私の環境では以下の通りになりました。
ACDOCA:300万レコード→実行結果:20レコード
A-1:2.9sec
A-2:1.0sec
B-1:0.018sec
B-2:0.018sec
C-1:3.0sec
純粋なITAB(Non-Pushdown)のA-1とC-1と比較して、PushdownしているB-1、B-2は100倍以上の処理速度となりました。
そして、HANA Infomation Viewはこれより更に10倍高速動作する可能性があります。
ABAP CDS Viewは、ABAP層で動作しているので、Open SQL(New, Classic含む)とほぼ同じ速度です。だから、使い慣れたOpen SQLにちょい足しをして、もっとカジュアルにCode Pushdownすると良いのではと思います。
2023-08-14:ラジオボタンで選択できるように修正。バグ修正
*&---------------------------------------------------------------------* *& Report SQL_Console *&---------------------------------------------------------------------* *& *&---------------------------------------------------------------------* REPORT SQL_Console. *----------------------------------------------------------------------- * GLOBAL VARIABLE *----------------------------------------------------------------------- DATA: GDS_BAPIRET2 TYPE BAPIRET2, "リターンパラメータ GDF_SUBRC TYPE SY-SUBRC. "リターンコード *----------------------------------------------------------------------- * CONDITION VIEW *----------------------------------------------------------------------- PARAMETERS P_ISDISP AS CHECKBOX TYPE UFVISIBLE DEFAULT ABAP_FALSE."表示フラグ PARAMETERS P_TBMAXS TYPE TBMAXSEL DEFAULT 1000000."選択するエントリの最大数 PARAMETERS: P_740A1 RADIOBUTTON GROUP RB1, "A-1:ACDOCAのデータを取得して、SORT命令で並び替えて、DELETE命令で重複を削除する P_740A2 RADIOBUTTON GROUP RB1, "A-2:ACDOCAのデータをORDER BY句で並び替えて取得して、"DELETE命令で重複を削除する P_740B1 RADIOBUTTON GROUP RB1, "B-1:ACDOCAのデータをDISTINCT句で重複削除して、ORDER BY句で並び替えて取得する P_740B2 RADIOBUTTON GROUP RB1, "B-2:ACDOCAのデータをGROUP BY句で重複削除して、ORDER BY句で並び替えて取得する P_740C1 RADIOBUTTON GROUP RB1. "C-1:番外編、ACDOCAのデータを取得して、LOOP + BINARY SEARCHで、重複削除および並び替えする *----------------------------------------------------------------------- * START-OF-SELECTION *----------------------------------------------------------------------- START-OF-SELECTION. CASE ABAP_TRUE. WHEN P_740A1. PERFORM START_OF_SELECTION_740A1 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_740A2. PERFORM START_OF_SELECTION_740A2 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_740B1. PERFORM START_OF_SELECTION_740B1 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_740B2. PERFORM START_OF_SELECTION_740B2 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_740C1. PERFORM START_OF_SELECTION_740C1 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN OTHERS. LEAVE TO LIST-PROCESSING. ENDCASE. *----------------------------------------------------------------------- * SUBROUTINE *----------------------------------------------------------------------- FORM START_OF_SELECTION_740A1 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "ACDOCAに登録済みの会社コードを並び替えて一覧出力する SELECT ACDOCA~RBUKRS FROM ACDOCA INTO TABLE @DATA(LDT_DATA). SORT LDT_DATA ASCENDING BY RBUKRS. DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING RBUKRS. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ). IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = DATA(LDO_ALV) CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG). POF_SUBRC = 8. RETURN. ENDTRY. DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ). SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_740A2 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "ACDOCAに登録済みの会社コードを並び替えて一覧出力する SELECT ACDOCA~RBUKRS FROM ACDOCA ORDER BY ACDOCA~RBUKRS INTO TABLE @DATA(LDT_DATA). DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING RBUKRS. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ). IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = DATA(LDO_ALV) CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG). POF_SUBRC = 8. RETURN. ENDTRY. DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ). SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_740B1 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "ACDOCAに登録済みの会社コードを並び替えて一覧出力する SELECT DISTINCT ACDOCA~RBUKRS FROM ACDOCA ORDER BY ACDOCA~RBUKRS INTO TABLE @DATA(LDT_DATA). DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ). IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = DATA(LDO_ALV) CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG). POF_SUBRC = 8. RETURN. ENDTRY. DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ). SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_740B2 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "ACDOCAに登録済みの会社コードを並び替えて一覧出力する SELECT ACDOCA~RBUKRS FROM ACDOCA GROUP BY ACDOCA~RBUKRS ORDER BY ACDOCA~RBUKRS INTO TABLE @DATA(LDT_DATA). DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ). IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = DATA(LDO_ALV) CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG). POF_SUBRC = 8. RETURN. ENDTRY. DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ). SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_740C1 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "ACDOCAに登録済みの会社コードを並び替えて一覧出力する SELECT ACDOCA~RBUKRS FROM ACDOCA INTO TABLE @DATA(LDT_DATA_1). DATA LDT_DATA LIKE LDT_DATA_1. LOOP AT LDT_DATA_1 ASSIGNING FIELD-SYMBOL(<LFS_DATA_1>). READ TABLE LDT_DATA TRANSPORTING NO FIELDS WITH KEY RBUKRS = <LFS_DATA_1>-RBUKRS BINARY SEARCH. IF SY-SUBRC <> 0. INSERT <LFS_DATA_1> INTO LDT_DATA INDEX SY-TABIX. CONTINUE. ENDIF. ENDLOOP. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ). IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = DATA(LDO_ALV) CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG). POF_SUBRC = 8. RETURN. ENDTRY. DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ). SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM.
参考までに、Non-SAP HANA(Oracle 10.2)で動作するSAP ERP 6.0で同様の検証をしてみました。
以下ソースコードは、ABAP 7.31で動作しています。そのため、Classic Open SQLで記述しています。
ACDOCAは無いので、BKPFで実装しました。
BKPF:32万レコード→実行結果:150レコード
A-1:0.21sec
A-2:0.15sec
B-1:0.10sec
B-2:0.11sec
C-1:0.22sec
データ量が少なかったのでドラスティックな差は出ませんでしたが、Non-PushdownのA-1、C-1が大体0.2sec、PushdownのB-1、B-2が大体0.1sec、半分ずつのA-2が結果も中間の0.15secとなりました。さすがにOracleも10.2くらい新しいと、Pushdownした方が良好な結果になりました。実際は、ITABを高速に扱うのは高度なスキルが必要と思います。過不足なくBINARY SEARCHを完璧に使えているプログラムはほとんどないと思います。だから実際はもっと差がつくと思います。
2023-08-14:ラジオボタンで選択できるように修正。
*&---------------------------------------------------------------------* *& Report SQL_Console *&---------------------------------------------------------------------* *& *&---------------------------------------------------------------------* REPORT SQL_Console. *----------------------------------------------------------------------- * GLOBAL VARIABLE *----------------------------------------------------------------------- DATA: GDS_BAPIRET2 TYPE BAPIRET2, "リターンパラメータ GDF_SUBRC TYPE SY-SUBRC. "リターンコード *----------------------------------------------------------------------- * CONDITION VIEW *----------------------------------------------------------------------- PARAMETERS P_ISDISP AS CHECKBOX TYPE UFVISIBLE DEFAULT ABAP_FALSE."表示フラグ PARAMETERS P_TBMAXS TYPE TBMAXSEL DEFAULT 1000000."選択するエントリの最大数 PARAMETERS: P_731A1 RADIOBUTTON GROUP RB1, "A-1:BKPFのデータを取得して、SORT命令で並び替えて、DELETE命令で重複を削除する P_731A2 RADIOBUTTON GROUP RB1, "A-2:BKPFのデータをORDER BY句で並び替えて取得して、"DELETE命令で重複を削除する P_731B1 RADIOBUTTON GROUP RB1, "B-1:BKPFのデータをDISTINCT句で重複削除して、ORDER BY句で並び替えて取得する P_731B2 RADIOBUTTON GROUP RB1, "B-2:BKPFのデータをGROUP BY句で重複削除して、ORDER BY句で並び替えて取得する P_731C1 RADIOBUTTON GROUP RB1. "C-1:番外編、BKPFのデータを取得して、LOOP + BINARY SEARCHで、重複削除および並び替えする *----------------------------------------------------------------------- * START-OF-SELECTION *----------------------------------------------------------------------- START-OF-SELECTION. CASE ABAP_TRUE. WHEN P_731A1. PERFORM START_OF_SELECTION_731A1 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_731A2. PERFORM START_OF_SELECTION_731A2 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_731B1. PERFORM START_OF_SELECTION_731B1 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_731B2. PERFORM START_OF_SELECTION_731B2 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN P_731C1. PERFORM START_OF_SELECTION_731C1 USING P_ISDISP "表示フラグ P_TBMAXS "選択するエントリの最大数 CHANGING GDS_BAPIRET2 "リターンパラメータ GDF_SUBRC. "リターンコード IF GDF_SUBRC <> 0. "リターンコード LEAVE TO LIST-PROCESSING. ENDIF. WHEN OTHERS. LEAVE TO LIST-PROCESSING. ENDCASE. *----------------------------------------------------------------------- * SUBROUTINE *----------------------------------------------------------------------- FORM START_OF_SELECTION_731A1 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "BKPFに登録済みの会社コードを並び替えて一覧出力する TYPES: BEGIN OF LTS_DATA, BUKRS TYPE BSEG-BUKRS, END OF LTS_DATA, LTT_DATA TYPE STANDARD TABLE OF LTS_DATA. DATA: LDT_DATA TYPE LTT_DATA. SELECT BKPF~BUKRS INTO TABLE LDT_DATA FROM BKPF. SORT LDT_DATA ASCENDING BY BUKRS. DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING BUKRS. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA LDF_DATA_COUNT TYPE INT4. DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT. IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- DATA: LDO_ALV TYPE REF TO CL_SALV_TABLE, LDX_SALV_MSG TYPE REF TO CX_SALV_MSG. TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = LDO_ALV CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO LDX_SALV_MSG. POF_SUBRC = 8. RETURN. ENDTRY. "ヘッダ表示 DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID. CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID. LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ). DATA LDF_COUNT3 TYPE INT4. SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3. LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_731A2 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "BKPFに登録済みの会社コードを並び替えて一覧出力する TYPES: BEGIN OF LTS_DATA, BUKRS TYPE BSEG-BUKRS, END OF LTS_DATA, LTT_DATA TYPE STANDARD TABLE OF LTS_DATA. DATA: LDT_DATA TYPE LTT_DATA. SELECT BKPF~BUKRS INTO TABLE LDT_DATA FROM BKPF ORDER BY BKPF~BUKRS. DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING BUKRS. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA LDF_DATA_COUNT TYPE INT4. DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT. IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- DATA: LDO_ALV TYPE REF TO CL_SALV_TABLE, LDX_SALV_MSG TYPE REF TO CX_SALV_MSG. TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = LDO_ALV CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO LDX_SALV_MSG. POF_SUBRC = 8. RETURN. ENDTRY. "ヘッダ表示 DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID. CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID. LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ). DATA LDF_COUNT3 TYPE INT4. SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3. LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_731B1 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "BKPFに登録済みの会社コードを並び替えて一覧出力する TYPES: BEGIN OF LTS_DATA, BUKRS TYPE BSEG-BUKRS, END OF LTS_DATA, LTT_DATA TYPE STANDARD TABLE OF LTS_DATA. DATA: LDT_DATA TYPE LTT_DATA. SELECT DISTINCT BKPF~BUKRS INTO TABLE LDT_DATA FROM BKPF ORDER BY BKPF~BUKRS. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA LDF_DATA_COUNT TYPE INT4. DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT. IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- DATA: LDO_ALV TYPE REF TO CL_SALV_TABLE, LDX_SALV_MSG TYPE REF TO CX_SALV_MSG. TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = LDO_ALV CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO LDX_SALV_MSG. POF_SUBRC = 8. RETURN. ENDTRY. "ヘッダ表示 DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID. CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID. LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ). DATA LDF_COUNT3 TYPE INT4. SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3. LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_731B2 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "BKPFに登録済みの会社コードを並び替えて一覧出力する TYPES: BEGIN OF LTS_DATA, BUKRS TYPE BSEG-BUKRS, END OF LTS_DATA, LTT_DATA TYPE STANDARD TABLE OF LTS_DATA. DATA: LDT_DATA TYPE LTT_DATA. SELECT BKPF~BUKRS INTO TABLE LDT_DATA FROM BKPF GROUP BY BKPF~BUKRS ORDER BY BKPF~BUKRS. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA LDF_DATA_COUNT TYPE INT4. DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT. IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- DATA: LDO_ALV TYPE REF TO CL_SALV_TABLE, LDX_SALV_MSG TYPE REF TO CX_SALV_MSG. TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = LDO_ALV CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO LDX_SALV_MSG. POF_SUBRC = 8. RETURN. ENDTRY. "ヘッダ表示 DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID. CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID. LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ). DATA LDF_COUNT3 TYPE INT4. SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3. LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM. FORM START_OF_SELECTION_731C1 USING PIF_ISDISP TYPE CHECKBOX PIF_TBMAXSEL TYPE TBMAXSEL CHANGING POS_BAPIRET2 TYPE BAPIRET2 POF_SUBRC TYPE SY-SUBRC. *----------------------------------------------------------------------- CLEAR: POS_BAPIRET2, "リターンパラメータ POF_SUBRC. "リターンコード * Please write the SQL statement here ☆ * Set the internal table to be stored to LDT_DATA ☆ * Inline definition of LDT_DATA is fun ☆ DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL. "タイムスタンプデータ取得開始 GET TIME STAMP FIELD LDF_TIMESTAMP_START. "タイムスタンプデータ取得開始 "BKPFに登録済みの会社コードを並び替えて一覧出力する TYPES: BEGIN OF LTS_DATA, BUKRS TYPE BSEG-BUKRS, END OF LTS_DATA, LTT_DATA TYPE STANDARD TABLE OF LTS_DATA. DATA: LDT_DATA TYPE LTT_DATA. DATA LDT_DATA_1 LIKE LDT_DATA. FIELD-SYMBOLS <LFS_DATA_1> LIKE LINE OF LDT_DATA_1. SELECT BKPF~BUKRS INTO TABLE LDT_DATA_1 FROM BKPF. LOOP AT LDT_DATA_1 ASSIGNING <LFS_DATA_1>. READ TABLE LDT_DATA TRANSPORTING NO FIELDS WITH KEY BUKRS = <LFS_DATA_1>-BUKRS BINARY SEARCH. IF SY-SUBRC <> 0. INSERT <LFS_DATA_1> INTO LDT_DATA INDEX SY-TABIX. CONTINUE. ENDIF. ENDLOOP. DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL. "タイムスタンプデータ取得終了 GET TIME STAMP FIELD LDF_TIMESTAMP_END. "タイムスタンプデータ取得終了 DATA LDF_DATA_COUNT TYPE INT4. DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT. IF PIF_ISDISP = ABAP_FALSE. CLEAR LDT_DATA. ENDIF. *----------------------------------------------------------------------- DATA: LDO_ALV TYPE REF TO CL_SALV_TABLE, LDX_SALV_MSG TYPE REF TO CX_SALV_MSG. TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = LDO_ALV CHANGING T_TABLE = LDT_DATA ). CATCH CX_SALV_MSG INTO LDX_SALV_MSG. POF_SUBRC = 8. RETURN. ENDTRY. "ヘッダ表示 DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID. CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID. LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ). LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ). DATA LDF_COUNT3 TYPE INT4. SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3. LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ). LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ). LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ). LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ). LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ). LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ). LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ). LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ). LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ). LDO_ALV->DISPLAY( ). POF_SUBRC = 0. ENDFORM.
当初は、DISTINCTとGROUP BYのどちらが速いか?をテーマにしようと思っていたのですが、急遽変更しました。
5年くらい前はGROUP BYの圧勝だったんだけれど、今回なんかねぇ~あまり差がつかなかったんだよね~。
以上
検索キーワード
ABAP
ABAP 7.31
ABAP 7.4
ABAP 7.50
ABAP 7.51
ABAP 7.52
SQL
Open SQL
New Open SQL
Classic Open SQL
ABAP SQL
SAP HANA
Code to Data
Code Pushdown
SAP ERP 6.0
SAP S/4HANA
最近のヘビロテです。
www.youtube.com