"
Etiqueta > performance
Apoiado por

Passar tabelas internas por valor é bom

Quando um método devolve um valor como RETURNING este é sempre passado por valor e não por referência. Muitas vezes faço métodos que devolvem tabelas internas, algumas bastante grandes. Mas sempre me preocupou a ideia de que, como está a ser devolvida por valor, o ABAP devolva uma cópia da tabela interna, algo que pode ter impacto na performance e na memória que o programa gasta.

Felizmente fiquei recentemente a saber que não é assim.

Ler o resto do artigo! »

Índices secundários em tabelas internas

Durante anos as tabelas internas eram declaradas assim:


DATA: itbl TYPE TABLE OF bkpf.

Ler o resto do artigo! »

DELETE vs CLEAR vs REFRESH vs FREE

DELETE
CLEAR
REFRESH
FREE

São várias maneiras de limpar os dados de uma tabela interna.
À partida parecem iguais.
Mas não são.

Ler o resto do artigo! »

Ensina o ABAP a fazer malabarismo

O que podemos fazer quando as noites não são suficientes para os processamentos diários?

Ler o resto do artigo! »

Boas prácticas
Usarás TRANSPORTING NO FIELDS

Muitas vezes fazes READ TABLE itbl ou LOOP AT itbl apenas para verificar se um registo existe (CHECK SY-SUBRC = 0). Ora para isso, os dados do registo não são realmente necessários. Nestes casos usa sempre TRANSPORTING NO FIELDS. Assim evitas ter de declarar uma estrutura destino e o programa fica mais rápido porque não tem de perder tempo a copiar dados.

Boas prácticas
INNER JOIN vs FOR ALL ENTRIES vs RANGES artificiais

Uma vez que as operações de dados estão muito mais optimizadas no servidor de base de dados do que no ABAP, é sempre preferível o primeiro. FOR ALL ENTRIES só deve ser usado quando não se conseguir fazer INNER JOIN (como com a BSEG por exemplo). Quando possível, usar RANGES artificiais é preferível a usar FOR ALL ENTRIES mas é preciso cuidado para não ultrapassar o limite do parser de SQL. Depende do servidor de base de dados mas regra geral é de evitar RANGES com mais de 1000 linhas.
Claro que ao usar FOR ALL ENTRIES nunca te podes esquecer de verificar que a tabela interna não está vazia caso contrário todas as entradas da tabela serão lidas.

Boas prácticas
Não farás SELECT *

Tenta seleccionar sempre apenas os campos que vais realmente usar. Escolher todos é um desperdício de recursos. Excepção feita ao uso das FM *_SINGLE_READ que, embora leiam os campos todos, fazem cache dos dados, sendo por isso ainda assim mais rápidos de usar quando usados múltiplas vezes com a mesma chave.
Se queres apenas verificar que um registo existe, selecciona apenas um campo, e se possível aquele que estás a usar como critério, evitando assim declarares uma variável extra. Exemplo: SELECT KUNNR INTO V_KUNNR FROM KNA1 WHERE KUNNR = V_KUNNR.
https://abapinho.com/2010/11/select-todos-os-campos/

Boas prácticas
Usarás FIELD-SYMBOLs em vez de variáveis de estrutura

READ TABLE itbl ASSIGNING é sempre mais rápido que READ TABLE itbl INTO wa.
Além disso, quando precisares de alterar dados em registos de uma tabela interna, assim não precisas de usar o comando MODIFY nem da variável auxiliar que às vezes usas para guardar o SY-TABIX.
A única situação em que uma variável de estrutura é aconselhada é quando queres adicionar linhas novas a uma tabela interna.
Algumas pessoas defendem que as variáveis de estrutura devem ser usadas sempre que não se quiser alterar os dados da tabela interna. Isto é mais lento, mas como convenção pode ser mais intuitivo.

SELECT dentro de SELECT

Provavelmente por razões históricas, os programadores ABAP não exploram as possibilidades do SQL. Muitos há que em vez de usarem INNER JOINs, ainda julgam que é mais rápido fazer vários SELECTs para tabelas internas e depois trabalhar os dados em ABAP. Mas a verdade é que, mesmo que se haja excepções, a regra é: quanto menos acessos à base de dados, melhor a performance. E faz sentido porque, afinal, porque foram escritas explicitamente para isso, as bases de dados relacionais são muito mais peritas em processar dados relacionais do que um programa ABAP.

Mas claro que há coisas que, pela sua complexidade, não podem ser feitas com um simples INNER JOIN. Ainda assim, algumas dessas coisas podem ser feitas num único SELECT.

Ler o resto do artigo! »

Com muitos campos evita INTO CORRESPONDING FIELDS

Já avisei aqui que, em tabelas com muitos campos, é sempre de evitar fazer SELECT *, devendo-se sempre seleccionar explicitamente apenas os campos necessários.

Mas não avisei ainda que há ainda outra optimização que merece ser feita: evitar o INTO CORRESPONDING FIELDS OF TABLE.

Ler o resto do artigo! »

SORTED em vez de STANDARD nas tabelas de cache

Há bastante tempo atrás escrevi aqui um artigo demonstrando as vantagens de usar tabelas internas com índices definidos em vez de simples tabelas STANDARD.

Confissão: é tal o hábito instalado que desde então, quase todas as tabelas internas que criei continuaram a ser STANDARD TABLE.

É muito frequente criar tabelas internas para fazer cache de dados que sei que vou utilizar amiúde dentro de LOOPs para evitar fazer SELECT SINGLEs lá pelo meio.

Fica a dica: sempre que criares uma tabela interna que populas com dados de cache, que só escreves uma vez mas vais ler muitas vezes, em vez de STANDARD, considera criá-la como SORTED e define-lhe decentemente uma chave. Compensa.

Agora que me confessei, espero ser absolvido e proponho emendar-me.

O Abapinho saúda-vos.

Análises parciais na SE30

Claro que já conheces a transacção SE30 (Análise de tempo de execução) e claro que a usas amiúde para analisar programas standard e descobrir nele tabelas, funções, BADIs e quejandos.

Ora se fores como eu, manténs uma relação de amor-ódio com esta transacção: se por um lado a amas por graças a ela consegues ver as entranhas de um programa sem ter de fazer debug, por outro lado odeia-la porque normalmente a lista de entranhas costuma ter milhares de linhas e tornar-se ingerível.

Mas eu já não sou como eu porque, desde que descobri que a SE30 permite fazer análises parciais, a minha relação com ela passou a ser de puro amor. E a partir de agora também tu poderás amá-la na sua totalidade porque vou ensinar-te este segredo.

  1. Transacção SE30;
  2. No bloco “Restrições de medição” cria uma variante com um nome qualquer diferente do DEFAULT;
  3. Na variante activa o pisco “Unidades determinadas”;
  4. Insere a transacção ou programa ou módulo de função a analisar;
  5. Carrega em “Executar” (normalmente agora a análise começaria mas, como escolhemos “unidades determinadas”, começa desligada e é preciso ligá-la explicitamente);
  6. Navega dentro do programa que estás a analisar até chegares ao ponto que queres analisar;
  7. Activa a análise escrevendo /ron lá em cima no campo de comandos;
  8. Faz o que tens a fazer;
  9. Desactiva a análise escrevendo lá em cima /roff;
  10. Sai do programa, voltando ao ecrã da SE30.

Acabaste de fazer uma análise parcial que, em vez dos típicos milhares de linhas, tem apenas as dezenas ou centenas de linhas que ocorreram entre os comandos /ron e /roff. Mais útil, não?

Aproveita o balanço e explora as outras possibilidades disponibilizadas pelas variantes de “restrição de medição”.

Obrigado a Michael Opoczynski pelo ensinamento.

E obrigado a * Cati Kaoe * pela foto.

O Abapinho saúda-vos.

LOOP ASSIGNING em vez de LOOP INTO

No princípio era o INTO.
Aliás, no princípio nem sequer era o INTO.

Ler o resto do artigo! »

Soneca

Volta não volta é preciso meter um programa a dormir. E como em quase tudo, há várias formas de o fazer, e umas formas são melhores do que outras.

A forma mais standard de conseguir isto em ABAP é a seguinte:


WAIT UP TO 10 SECONDS.

A vantagem do WAIT UP TO N SECONDS é que o processo é libertado durante estes 10 segundos, ficando assim disponível para quem o quiser apanhar. A grande desvantagem é que faz um COMMIT implícito, o que nem sempre é bom. Se não te importares com o COMMIT, esta é a melhor forma de adormeceres o teu programa. Nota que não dá para o adormecer por 1.5 segundos pois o parâmetro só aceita números inteiros.

Se um COMMIT não der jeito, porque tens um cursor aberto para a base de dados ou porque estás a meio de uma transacção, podes sempre fazer isto:


DATA: ZTIME LIKE SY-UZEIT.

GET TIME.

ZTIME = SY-UZEIT + 10.

DO.
  GET TIME.
  IF SY-UZEIT >= ZTIME.
     EXIT.
   ENDIF.
ENDDO.

Mas fazer isto é muito parvo. Chama-se espera activa e é a última coisa que queres fazer num programa porque é o mesmo que metê-lo a correr numa passadeira de ginásio: cansa-se e não chega a lado nenhum.

Felizmente há uma alternativa mais saudável que, embora não liberte o processo, evita o malfadado COMMIT:


CALL FUNCTION 'ENQUE_SLEEP'
    EXPORTING
        seconds    = 10.

O Abapinho saúda-vos.

Obrigado Sweet-Rainb0w pela foto.

Partida… lagarta… fugida!

Senhoras e senhores, meninos e meninas, a corrida está prestes a começar.

Introdução

Apresento-vos as 4 participantes. São 4 tabelas internas, de diferentes raças e credos, que se vão pelejar pelo título atlético do LOOP em velocidade. Aqui estão elas:

Concorrente 1: DATA: LT_ITEM TYPE TABLE
Concorrente 2: DATA: LT_ITEM_HASHED TYPE HASHED TABLE
Concorrente 3: DATA: LT_ITEM_SORTED TYPE SORTED TABLE
Concorrente 4: DATA: LT_ITEM TYPE TABLE + INTO INDEX

Ler o resto do artigo! »


Acerca do Abapinho
O Abapinho é suportado pelo WordPress
Artigos (RSS) e Comentários (RSS).