PDA

Ver la Versión Completa : mejora rendimiento


budista1
09/11/10, 13:24:01
¿Cómo mejoro rendimiento a estos 2 selects? (alternativas)

SELECT * INTO TABLE it_ass_tipus
FROM zef_ass_tipus
WHERE retencio_irpf = 'X' AND
tipus_ajust <> '/'.

* Obtenim les dades de la sac
SELECT * INTO TABLE it_sac
FROM zef_sac FOR ALL ENTRIES IN it_ass_tipus
WHERE bukrs = p_bukrs AND
gjahr = p_gjahr AND
id_tipus_ass = it_ass_tipus-tipus_complert AND
belnr IN s_belnr AND
tercer IN s_tercer AND
estat IN s_estat AND
estat <> '99' AND
hkont IN s_hkont AND
tercer IN r_terc.

GRACIAS Y SALUDOS ABAPEROS

jtristan
09/11/10, 14:06:37
Desconociendo el tamaño de las tablas así como los índices que estén creados podrías hacer un JOIN en vez de un FOR ALL ENTRIES. El for all entries sino recuerdo mal no deja de ser un UNION por cada registro de la tabla temporal.

Sería algo así:
SELECT * INTO TABLE table
FROM zef_ass_tipus
LEFT JOIN
zef_sac
ON
zef_ass_tipus~tipus_complert = zef_sac~id_tipus_ass
WHERE retencio_irpf = 'X' AND
tipus_ajust <> '/' AND
bukrs = p_bukrs AND
gjahr = p_gjahr AND
belnr IN s_belnr AND
tercer IN s_tercer AND
estat IN s_estat AND
estat <> '99' AND
hkont IN s_hkont AND
tercer IN r_terc.


Un saludo.

budista1
09/11/10, 15:55:29
Gracias compañero!!

voy a probarlo.

La tabla ZEF_SAC tiene unos 300 mil registros, los campos clave son

MANDT
BUKRS
GJAHR
NUM_SAC

La tabla ZEF_ASS_TIPUS solo unos 500 registros

campos clave :
MANDT
TIPUS
ESTAT


Por qué transacción puedo evaluar el rendimiento?
(a parte de la se30)

Saludos!

Mari.Sole
09/11/10, 23:06:58
Hola,
Una simple acotación. Podrías probar de eliminar del SELECT la clausula <> eso hace que se pierda mucha performance en el acceso a la BD.
Si eliminas esa cluasula luego de la selección de datos deberías agregar una rutina que al resultado obtenido de esa selección (almacenado en tabla interna) deberías recorrerla y eliminar los registros cuya condicion quitaste del SELECT.

Saludos!

VLozano
10/11/10, 07:03:59
Antes que nada:
1. FOR ALL ENTRIES:
si vas a usar la cláusula FOR ALL ENTRIES IN, asegúrate primero de que la tabla interna sobre la que se va a filtrar tiene datos.SELECT fields
INTO TABLE it_tab1
FROM table
WHERE conditions.
DESCRIBE TABLE it_tab1.
IF sy-tfill > 0.
SELECT fields2
INTO TABLE it_tab2
FROM table2
FOR ALL ENTRIES IN it_tab1
WHERE conditions2.
ENDIF.
En tu caso, si la primera SELECT no retorna datos, la segunda lee TODOS LOS REGISTROS DE LA TABLA. Y eso duele.

2. SELECT *
No es conveniente utilizar esta sentencia. Es mucho más rápido de escribir, pero a no ser que realmente necesites todos los datos de la tabla, estás metiéndole presión al servidor de datos (y al de aplicaciones).
------------------------------------------------------------------
Y ahora una respuesta (que quizá no te guste)

Alternativas al FOR ALL ENTRIES:
- INNER JOIN
- SELECT SINGLE en un LOOP

La mayoría de desarrolladores "a la antigua" (entre los que me podrías incluir) te dirían que la última es un suicidio. No es cierto. La elección entre las tres posibilidades depende de la cantidad (y reparto entre tablas) de datos a leer, de si se utilizan los índices en las condiciones de selección, y de la carga de memoria que pueda tolerar tu servidor.

Viendo las condiciones de la segunda SELECT, podríamos deducir que el campo que usas para filtrar en el FOR ALL ENTRIES no forma parte de la clave ni empieza un índice. Si es el caso, el INNER JOIN podría llegar a ser contraproducente.

Si las cláusulas WHERE que has dado usan índices, y el rendimiento sigue siendo malo (¿seguro que el cuello de botella está ahí?), quizá deberías usar otra aproximación al problema. Por ejemplo, si realizas un tratamiento masivo en un LOOP posterior sobre la primera tabla, en el que realizas un READ TABLE para coger los datos de la segunda, quizá te interesaría intentar un SELECT-LOOP-SELECT. Mucha gente se llevaría ahora las manos a la cabeza, pero con los nuevos motores de BBDD y el rendimiento del que son capaces los servidores hoy en día, ese gesto está desfasado. Te lo dice un abuelete.
SELECT fields
INTO TABLE t_tab1
FROM tab1
WHERE conditions.
LOOP AT t_tab1 INTO w_tab1.
REFRESH t_tab2.
SELECT fields2
INTO TABLE t_tab2
FROM tab2
WHERE conditions2. "añadiendo las condiciones sobre w_tab1
LOOP AT t_tab2 INTO w_tab2.
* Trabajo
ENDLOOP.
ENDLOOP.

budista1
10/11/10, 10:36:43
Antes de nada, muy agradecido por vuestra ayuda.

Hice una 1a prueba cambiando unas selects por el join que me dijo un compañero de mundosap. De momento el rendimiento no ha mejorado :-(

SELECT * INTO CORRESPONDING FIELDS OF TABLE it_sac
FROM zef_sac
LEFT JOIN
zef_ass_tipus
ON
zef_sac~id_tipus_ass = zef_ass_tipus~tipus_complert
WHERE
* retencio_irpf = 'X'
*AND
*tipus_ajust <> '/' AND
bukrs = p_bukrs AND
gjahr = p_gjahr AND
belnr IN s_belnr AND
tercer IN s_tercer AND
*estat IN s_estat AND
*estat <> '99' AND
hkont IN s_hkont AND
tercer IN r_terc.

robert_milan
10/11/10, 10:41:51
¿Cómo mejoro rendimiento a estos 2 selects? (alternativas)
* it_ass_tipus definela con campos que necesites *
* it_sac definela con campos que necesites *
SELECT [Pon los campos que necesites] INTO TABLE it_ass_tipus
FROM zef_ass_tipus
WHERE retencio_irpf = 'X' AND
tipus_ajust <> '/'.
If sy-subrc = 0.
* Obtenim les dades de la sac
SELECT [Pon los campos que necesites] INTO TABLE it_sac
FROM zef_sac FOR ALL ENTRIES IN it_ass_tipus
WHERE bukrs = p_bukrs AND
gjahr = p_gjahr AND
id_tipus_ass = it_ass_tipus-tipus_complert AND
belnr IN s_belnr AND
tercer IN s_tercer AND
estat IN s_estat AND
estat <> '99' AND
hkont IN s_hkont AND
tercer IN r_terc.

A la tabla ZEF_SAC creale un indice con los campos que usas aqui.
endif.

Saludos

budista1
10/11/10, 16:15:01
Y si hago 2 selects normales, lo meto en 2 tablas internas y luego hago

un loop de una tabla
y read table binary search con la otra?

Podría mejorar la cosa:p

VLozano
11/11/10, 06:33:47
Y si hago 2 selects normales, lo meto en 2 tablas internas y luego hago

un loop de una tabla
y read table binary search con la otra?

Podría mejorar la cosa:p
Eso dependerá de algunos factores, como el número de registros de cada tabla (sobretodo de la segunda), la memoria del servidor, su configuración...

Yo antes que intentar eso haría pruebas de rendimiento con un SELECT-LOOP-SELECT, como te he comentado antes. Siempre estás a tiempo de echarte atrás, pero probablemente te sorprendas.