Análise e teste de código
Utilização correta de tipos de dados e conversões de tipo
Processamento de campos de caracteres
Uso de push-down de código no ABAP SQL
Melhorar o desempenho da tabela interna
Implementar verificações de autorização
Projetando código efetivo orientado a objetos
Definir e trabalhar com classes de exceção
Adicionar documentação à codificação ABAP

Trabalhar com tabelas ordenadas e hash

Objective

After completing this lesson, you will be able to trabalhar com tabelas ordenadas e hash.

Experimente: preparação de exemplo de código

  1. Selecione Ctrl + Shift + N para criar um novo objeto do repositório ABAP.
  2. Digite a palavra banco de dados no campo de filtro, marque o resultado da pesquisa Tabela de banco de dados e selecione Continuar.
  3. Atribua o novo objeto ao pacote com o qual você está trabalhando e insira o nome ZS4D401_FLIGHTS. Insira uma descrição para a tabela e selecione Seguinte.
  4. Atribua o objeto a uma ordem de transporte e selecione Concluir.
  5. Insira o seguinte código entre chaves:
    Code Snippet
    1234567891011
    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;
  6. Selecione Ctrl + F3 para ativar a tabela.
  7. Crie uma nova classe ABAP chamada ZCL_FILL_ZS4D401_FLIGHTS.
  8. Insira o seguinte código na implementação do método main:
    Code Snippet
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
    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| ).
  9. Selecione Ctrl + F3 para ativar a classe.
  10. Selecione F9 para executar a classe. O método main preenche uma tabela de banco de dados adicional que é necessária para os snippets de código nas duas seções seguintes.

Tabelas ordenadas e hash

Até agora, trabalhamos com tabelas internas padrão. Os dados em uma tabela padrão não são mantidos em uma determinada sequência de ordenação. Consequentemente, quando você lê dados da tabela, o sistema deve procurar a tabela sequencialmente até encontrar a linha ou linhas necessárias. Dependendo do tamanho da tabela, isso pode demorar algum tempo.

Você pode otimizar a performance de acessos de leitura a tabelas internas usando tabelas ordenadas ou hash.

Em uma tabela ordenada, o conteúdo da tabela é sempre ordenado de acordo com os campos-chave em ordem crescente. Quando você insere um novo registro na tabela, o sistema garante que ele seja colocado na posição correta. Como os dados são sempre ordenados, o sistema pode recuperar registros de forma mais eficiente do que a partir de uma tabela padrão (desde que você siga determinadas regras).

As tabelas hash são gerenciadas usando um algoritmo hash especial. Isso garante que o sistema possa recuperar registros muito rapidamente, mesmo se a tabela for extremamente grande. No entanto, esse ganho de performance só funciona em casos muito específicos.

Acesso a uma tabela ordenada

Neste vídeo, você verá como acessar uma tabela ordenada.

Quando você declara uma tabela hash, deve defini-la com uma chave única – nunca são permitidas duplicatas.

Assista ao vídeo para saber como acessar uma tabela hash.

Quando utilizar tabelas padrão, ordenadas e hash

Se você preencher uma tabela interna e, subsequentemente, implementar um loop sobre toda a tabela, pode usar uma tabela padrão. A otimização da performance de tabelas ordenadas e hash é irrelevante, uma vez que não existe nenhum filtro no loop.

Este exemplo mostra quando você deve usar tabelas ordenadas e hash. Ele contém um loop sobre as conexões de tabela usando o primeiro campo-chave na cláusula where. Este é um caso para a utilização de uma tabela ordenada, uma vez que o sistema pode utilizar a técnica de pesquisa binária mesmo que a chave não esteja completamente indicada.

Dentro do loop, o programa procura entradas na tabela companhias aéreas. Por isso, existem acessos repetidos à tabela usando a chave completa. Este é um caso ideal para usar uma tabela hash.

Tempos de execução comparativos de tabelas padrão, ordenadas e hash

Esta figura compara os tempos de execução de tabelas padrão, ordenadas e hash.

Preenchimento de tabelas ordenadas e hash

Quando você usa uma tabela padrão, pode usar a instrução APPEND para adicionar o conteúdo de uma área de trabalho ao final da tabela. Isso não é possível com tabelas hash e leva a um erro de sintaxe.

Tecnicamente, você pode utilizar a instrução APPEND para preencher uma tabela ordenada. No entanto, você corre o risco de causar um erro em tempo de execução se a linha que você tenta anexar não pertencer ao final da tabela de acordo com a sequência de ordenação. Isso aconteceria em nosso exemplo.

A maneira de preencher uma tabela hash e preencher uma tabela ordenada com segurança é usar a instrução INSERT. INSERT garante que a nova linha seja inserida na posição correta na tabela.

Experimente: tabelas ordenadas e hash

  1. Crie uma nova classe que implemente a interface IF_OO_ADT_CLASSRUN.
  2. Copie o seguinte snippet de código para a parte de implementação do método if_oo_adt_classrun~main( ):
    Code Snippet
    1234567891011
    * 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| ).
  3. Mude para a guia Tipos locais e copie o seguinte snippet de código para o editor:
    Code Snippet
    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
    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.
  4. Selecione Ctrl + F3 para ativar a classe.
  5. Clique com o botão direito do mouse no Editor e selecione Perfil como...Aplicação ABAP (console).
  6. Em Detalhes, desmarque o campo de seleção Acesso ao banco de dados SQL e selecione Concluir.
  7. Mude para a perspectiva Profiler ABAP e clique duas vezes no item de rastreamento (talvez seja necessário atualizar a exibição primeiro).
  8. Selecione Lista de ocorrências.
  9. Compare os tempos de execução dos métodos access_standard( ), access_sorted( ) e access_hashed( ).

Trabalhar com tabelas ordenadas e hash

Você percebe que seu código contém grandes tabelas internas do tipo Tabela padrão. Você analisa a forma como essas tabelas são acessadas no código e descobre que elas só são acessadas por chave. Para melhorar a performance, você modifica a definição das tabelas internas para Tabela ordenada ou Tabela hash, dependendo da forma como são acessadas.

Modelo:

  • /LRN/CL_S4D401_ITS_FSYM (classe global)

Solução:

  • /LRN/CL_S4D401_ITS_TABLE_KIND (classe global)

Tarefa 1: Copiar modelo (opcional)

Copie a classe modelo /LRN/CL_S4D401_ITS_FSYM. Se você tiver concluído o exercício anterior, pode ignorar esta tarefa e continuar processando sua classe ZCL_##_SOLUTION.

Etapas

  1. Copie a classe /LRN/CL_S4D401_ITS_FSYM para uma classe em seu próprio pacote (nome sugerido: ZCL_##_SOLUTION, onde ## representa seu número de grupo).

    1. No Explorador de projetos, clique com o botão direito do mouse na classe /LRN/CL_S4D401_ITS_FSYM para abrir o menu de contexto.

    2. No menu de contexto, selecione Duplicar....

    3. Insira o nome do seu pacote no campo Pacote. No campo Nome, insira ZCL_##_SOLUTION, em que ## representa seu número de grupo.

    4. Selecione Avançar.

    5. Confirme a ordem de transporte e selecione Concluir.

  2. Ative a cópia.

    1. Pressione Ctrl + F3 para ativar a classe.

Tarefa 2: Ajustar CONNECTIONS_BUFFER

Utilize a lista de utilizações para o atributo estático connections_buffer da classe local LCL_PASSENGER_FLIGHT. Modifique a definição de connections_buffer para que ela melhor se adapte à forma como é acessada.

Etapas

  1. Navegue para a definição do atributo estático connections_buffer na classe local LCL_PASSENGER_FLIGHT.

    1. Por exemplo, expanda o nó LCL_PASSENGER_FLIGHT na visão Estrutura e selecione CONNECTIONS_BUFFER.

  2. Crie a lista de utilizações para o atributo connections_buffer.

    1. Na instrução CLASS-DATA, clique com o botão direito do mouse em connections_buffer e selecione Obter lista de utilizações. Como alternativa, você pode posicionar o cursor em connections_buffer e pressionar Ctrl + Shift + G.

    2. Analise a lista na visão Pesquisar abaixo do editor. Posicione o cursor sobre um resultado para exibir a instrução completa.

  3. Ajuste a definição do atributo connections_buffer. Selecione o tipo de tabela e a definição de chave mais adequados ao acesso de leitura.

    1. Modifique o tipo de tabela para HASHED TABLE.

    2. Modifique a definição de chave para uma chave única com carrier_id e connection_id como campos-chave.

    3. Ajuste o código da seguinte forma:

      ABAP
      1234
      * 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.

Tarefa 3: Ajustar FLIGHTS_BUFFER

Use a lista de utilizações para o atributo estático flights_buffer da classe local LCL_PASSENGER_FLIGHT. Modifique a definição de flights_buffer de modo que ela melhor se adapte à forma como o atributo é acessado.

Etapas

  1. Navegue para a definição do atributo estático flights_buffer na classe local LCL_PASSENGER_FLIGHT.

    1. Por exemplo, expanda o nó LCL_PASSENGER_FLIGHT na visão Estrutura e selecione FLIGHTS_BUFFER.

  2. Crie a lista de utilizações para o atributo flights_buffer.

    1. Na instrução CLASS-DATA, clique com o botão direito do mouse em flights_buffer e selecione Obter lista de utilizações. Como alternativa, você pode posicionar o cursor em flights_buffer e pressionar Ctrl + Shift + G.

    2. Analise a lista na visão Pesquisar abaixo do editor. Posicione o cursor sobre um resultado para exibir a instrução completa.

  3. Ajuste a definição do atributo flights_buffer. Selecione o tipo de tabela e a definição de chave mais adequados aos acessos de leitura.

    1. Modifique o tipo de tabela para SORTED TABLE.

    2. Modifique a definição da chave para uma chave não única com carrier_id, connection_id e flight_date como campos-chave.

    3. Ajuste o código da seguinte forma:

      ABAP
      1234
      * 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.
  4. Analise os erros de sintaxe na visão Problemas.

    1. Analise a visão Problemas abaixo do editor.

  5. Remova ou comente a instrução SORT redundante.

    1. Ajuste o código da seguinte forma:

      ABAP
      1
      * SORT flights_buffer BY carrier_id connection_id flight_date.
  6. Ative e teste sua classe global como aplicativo de console.

    1. Pressione Ctrl + F3.

    2. Pressione F9.

Tarefa 4: Quantificar a melhoria

Utilize o Profiling ABAP para quantificar a melhoria da performance alcançada ajustando o tipo das duas tabelas internas.

Etapas

  1. Localize a classe modelo /LRN/CL_S4D401_ITS_FSYM no Explorador de projetos.

  2. Defina o perfil da classe modelo /LRN/CL_S4D401_ITS_FSYM como um app de console ABAP.

    1. Clique com o botão direito na classe modelo /LRN/CL_S4D401_ITS_FSYM no Explorador de projetos e selecione Perfil comoAplicação ABAP (console).

    2. Selecione Concluir.

    3. Aguarde até que a visão Console seja exibida ou atualizada.

  3. Retorne à sua própria classe (ZCL_##_SOLUTION, onde ## é seu número de grupo) e crie o perfil da mesma forma.

    1. Localize sua própria classe no Explorador de projetos.

    2. Clique com o botão direito em sua classe no Explorador de projetos e selecione Perfil comoAplicativo ABAP (console).

    3. Aguarde até que a visão Console seja exibida ou atualizada.

  4. Mude para a perspectiva Profiling ABAP e compare os dois rastreamentos ABAP.

    1. Para abrir a perspectiva Profiling ABAP, selecione WindowPerspectiveOpen PerspectiveOther....do menu de eclipse. Em seguida, selecione Profiling ABAP e Abrir. (Como alternativa, se disponível, você pode selecionar o ícone Profiling ABAP no canto superior direito da barra de ferramentas de eclipse.)

    2. Na visão Rastreamentos ABAP, na parte inferior, expanda o nó que corresponde ao seu projeto ABAP Cloud.

    3. Pressione F5 para atualizar a lista de resultados de rastreamento. Os dois primeiros resultados de rastreamento devem ser nomeados como sua própria classe ABAP e a classe modelo.

    4. Compare os valores na coluna Tempo de execução (s).

  5. Após a análise, retorne à perspectiva ABAP.

    1. Mude a perspectiva como fez anteriormente.