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.
Fiz as seguintes experiências com a tabela BSAD:
- Seleccionar a tabela inteirinha para uma tabela interna com a mesma estrutura;
- Seleccionar apenas 4 campos para uma tabela interna com a estrutura da BSAD usando INTO CORRESPONDING FIELDS;
- Seleccionar apenas 4 campos da tabela BSAD para uma tabela interna com apenas esses 4 campos ainda assim usando INTO CORRESPONDING FIELDS;
- Seleccionar apenas 4 campos da tabela BSAD
Eis os resultados:
Duração | % | x | |
---|---|---|---|
1 | 54.12s | 100% | |
2 | 3.40s | 6.3% | 16x |
3 | 0.74s | 1.4% | 71x |
4 | 0.70s | 1.3% | 77x |
Traduzindo a coisa para miúdos:
- Tragédia. Evita a todo o custo. Mas isto já nós sabíamos;
- Seleccionando os campos demora apenas 6.3%, ou seja, é quase 16x mais rápido do que a abordagem javarda e preguiçosa;
- Enviando os campos para uma estrutura pequena em vez de para a estrutura grande demora apenas 1.4%. É 71x mais rápido do que a abordagem trágica e 4.5x mais rápido do que a que já tínhamos aconselhado;
- Evitando o uso do INTO CORRESPONDING quando a estrutura já é pequena ainda se ganha ligeiramente, mas nada de muito significativo.
Foste avisado.
Nota que a vantagem do uso do INTO CORRESPONDING FIELDS é introduzir alguma segurança pois mapeia os campos automaticamente. Caso este comando não seja usado é necessário garantir que os campos da estrutura destino estão todos lá e pela mesma ordem em que aparecem no SELECT.
Fica aqui o programa usado para obter estes resultados:
REPORT zzt_into_corresponding.
TYPES: BEGIN OF ty_campos,
bukrs TYPE bukrs,
belnr TYPE belnr_d,
gjahr TYPE gjahr,
buzei TYPE buzei,
END OF ty_campos.
DATA: t_bsad_todos TYPE STANDARD TABLE OF bsad,
t_bsad_poucos type STANDARD TABLE OF bsad,
t_campos TYPE STANDARD TABLE OF ty_campos,
rtime0 TYPE i,
rtime1 TYPE i,
rtime2 TYPE i,
rtime3 type i,
rtime4 type i.
GET RUN TIME FIELD rtime0.
SELECT * FROM bsad
INTO CORRESPONDING FIELDS OF TABLE t_bsad_todos.
GET RUN TIME FIELD rtime1.
SELECT bukrs belnr gjahr buzei FROM bsad
INTO CORRESPONDING FIELDS OF TABLE t_bsad_poucos.
GET RUN TIME FIELD rtime2.
SELECT bukrs belnr gjahr buzei FROM bsad
INTO CORRESPONDING FIELDS OF TABLE t_campos.
GET RUN TIME FIELD rtime3.
SELECT bukrs belnr gjahr buzei FROM bsad
INTO TABLE t_campos.
GET RUN TIME FIELD rtime4.
rtime0 = rtime1 - rtime0.
rtime1 = rtime2 - rtime1.
rtime2 = rtime3 - rtime2.
rtime3 = rtime4 - rtime3.
WRITE: / 'SELECT *', 50 rtime0,
/ 'SELECT campos INTO CORRESPONDING', 50 rtime1,
/ 'SELECT campos INTO CORRESPONDING estrutura', 50 rtime2,
/ 'SELECT campos INTO estrutura', 50 rtime3.
Para os mais picuinhas, é certo que para obter valores mais precisos seria necessário correr isto várias vezes e variar a ordem para obter médias e contornar caches. Mas as diferenças são tão gritantes que não restasm grandes dúvidas. Além disso experimentei inverter a ordem dos SELECTs e as proporções mantiveram-se.
Obrigado Sérgio Fraga pela dica.
Obrigado a metalkpirate1day pela foto.
O Abapinho saúda-vos.
5 de Julho de 2013 às 1:23
Ola Nuno,
Ando meio sumido do seu blog, e quando apareco para discordar de ti. Veja esse blog post na SCN, feito pelo Thomas Zloch: http://scn.sap.com/docs/DOC-33976
Abraco
Custodio
8 de Julho de 2013 às 9:39
Olá Custodio, realmente é intringante. Obrigado por me mostrares isto. Vou ter de comparar os meus exemplos com os exemplos por ele apresentados. Porque os meus exemplos realmente mostram que o MOVE-CORRESPONDING é mais lento. Deve depender das situações.
27 de Fevereiro de 2014 às 18:20
Ola,
Na minha humilde opinião, esse código não é válido para comparação de tempos de execução, da forma como foi proposto.
Sempre que fazemos o PRIMEIRO acesso a uma informação qualquer no banco de dados, esta SEMPRE levará mais tempo do que os demais acessos à mesma informação, isto se deve pelo fato de no primeiro acesso não existir dados em cache no servidor de banco de dados.
Se voce repetir 2 vezes o mesmo “SELECT *” nesse seu exemplo, vai notar que na segunda vez ele irá rodar extremamente mais rápido que na primeira vez, pois nesta segunda vez, como o servidor de banco de dados já fez cache em memória RAM, ele não irá ler dados fisicamente no disco rígido (que é lento), ao invés disso, ele vai ler diretamente do cache em memória RAM (que é muito mais rápido).
Faça o teste no seu código, adicione uma variável “rtime5” e repita o “SELECT *” logo após o primeiro “SELECT *” e veja os tempos de execução.
Abraço,
Gian
28 de Fevereiro de 2014 às 16:49
Olá Giancarlo,
De facto, tens toda a razão. O teste é muito pouco científico :) Ainda assim, experimentei inverter a ordem dos SELECTs (sabendo que uns continuam a afectar os outros) e os resultados foram consistentes:
SELECT campos INTO estrutura 24.955
SELECT campos INTO CORRESPONDING estrutura 24.512
SELECT campos INTO CORRESPONDING 144.042
SELECT * 956.909
Mas o mais cómico é que por engano corri o programa no mandante de desenvolvimentos, que não tem dados (a BSAD tem 0 registos) e o mais rápido foi de longe o SELECT * eh eh