PDA

Ver la Versión Completa : Performance de una select


javibest
16/01/09, 11:30:24
Tengo un par de selects para recoger documentos contables a partir de :

Sociedad
Fecha de contabilizacion
Cuenta de mayor.

FORM get_data.

SELECT * INTO TABLE gt_bkpf
FROM bkpf
WHERE bukrs IN p_bukrs
AND bstat = space
AND budat IN p_budat
AND blart IN p_blart
AND gjahr IN s_gjahr.

CLEAR gt_bseg.
REFRESH gt_bseg.

LOOP AT gt_bkpf.
SELECT * APPENDING TABLE gt_bseg
FROM bseg
WHERE bukrs = gt_bkpf-bukrs
AND belnr = gt_bkpf-belnr
AND gjahr = gt_bkpf-gjahr
AND hkont IN p_hkont.

ENDLOOP.

ENDFORM. " get_data

el tema es que para una rango de fechas de contabilizacion de 12 meses tarda casi 30 minutos, mientras que la FBL3N tarda 1 minuto.

Alguien sabe como puedo depurar esta consulta a la bbdd para que sea mas rapida?

Gracias

ballan
16/01/09, 12:04:50
Tengo un par de selects para recoger documentos contables a partir de :

Sociedad
Fecha de contabilizacion
Cuenta de mayor.

FORM get_data.

SELECT * INTO TABLE gt_bkpf
FROM bkpf
WHERE bukrs IN p_bukrs
AND bstat = space
AND budat IN p_budat
AND blart IN p_blart
AND gjahr IN s_gjahr.

CLEAR gt_bseg.
REFRESH gt_bseg.

LOOP AT gt_bkpf.
SELECT * APPENDING TABLE gt_bseg
FROM bseg
WHERE bukrs = gt_bkpf-bukrs
AND belnr = gt_bkpf-belnr
AND gjahr = gt_bkpf-gjahr
AND hkont IN p_hkont.

ENDLOOP.

ENDFORM. " get_data

el tema es que para una rango de fechas de contabilizacion de 12 meses tarda casi 30 minutos, mientras que la FBL3N tarda 1 minuto.

Alguien sabe como puedo depurar esta consulta a la bbdd para que sea mas rapida?

Gracias

Lo que ralentiza muchisimo es el

LOOP AT gt_bkpf.
SELECT * APPENDING TABLE gt_bseg
FROM bseg
WHERE bukrs = gt_bkpf-bukrs
AND belnr = gt_bkpf-belnr
AND gjahr = gt_bkpf-gjahr
AND hkont IN p_hkont.

ENDLOOP.

deberias utilizar FOR ALL ENTRIES

SELECT *
APPENDING TABLE gt_bseg
FROM bseg
FOR ALL ENTRIES IN gt_bkpf
WHERE bukrs = gt_bkpf-bukrs
AND belnr = gt_bkpf-belnr
...

Otra cosa que mejorara el rendimiento es que en lugar de hacer SELECT * solo cojas los campos que necesitas y los seleccionas en el mismo orden en el que estan definidos en la tabla

oalanis
16/01/09, 15:51:52
que tal javibest, si lo que necesitas es solo los datos en tu tabla interna gt_bseg podrías utilizar un JOIN entre ambas tablas, seria algo así:

FORM get_data.

CLEAR gt_bseg.
REFRESH gt_bseg.

SELECT
B~campo1
B~campo2
B~campo3
A~campoX
"... los campos que requieres de tu tabla bseg (B) o de la bkpf (A)
INTO CORRESPONDING FIELDS OF TABLE gt_bseg
FROM bkpf as A
JOIN bseg as B
ON A~bukrs = B~bukrs
AND A~belnr = B~belnr
AND A~gjahr = B~gjahr
WHERE A~bukrs IN p_bukrs
AND A~bstat IN p_bstat
AND A~budat IN p_budat
AND A~blart IN p_blart
AND A~gjahr IN p_gjahr
AND B~hkont IN p_hkont
.
ENDFORM. " get_data


espero te sea de ayuda.

DavidXD_XD
16/01/09, 16:28:08
Hola oalanis, lo que dices no es del todo cierto ... un buen metodo es el INNER JOIN pero para los casos de tablas cluster como la BSEG se usa los FOR ALL ENTRIES como menciona ballan ... un saludo !!

oalanis
16/01/09, 17:12:02
Que tal david, tienes razón, se me estaba pasando ese grandisimo detalle :o una disculpa, por mi respuesta errónea, gracias por corregir.

Mauricio Hidalgo
16/01/09, 17:12:08
Pero mejor que usar la BSEG es usar las tablas que forman la BSEG, como BSAD, BSID, BSAK, BSIK, entre otras que componen el cluster.

¿Creo o me equivoco?

Saludos

DavidXD_XD
16/01/09, 19:23:49
Sep, es correcto, si tienes los proveedores, materiales o codigos de clientes a la mano seria mejor con esas tablas y tbm usar el JOIN para agilizar las busquedas

Edd_401
19/01/09, 03:37:18
Coincido con Maurio y tal vez un indice estaria a la tabla bien .

El 'for all entries' ...........

bisonye
19/01/09, 07:07:41
Coincido con Maurio y tal vez un indice estaria a la tabla bien .

El 'for all entries' ...........

No puedes crear un índice en la bseg, es una tabla cluster.

Por lo que veo quiere imitar el rendimiento de la FBL3N que es el listado de cuentas de mayor. Creo que la mejor solución es utilizar las tablas BSIS y BSAS dependiendo de si se tratan de partidas abiertas o compensadas y olvidarse de la BKPF y la BSEG.

Saludos

javibest
19/01/09, 10:10:59
Muchas gracias a todos.

el programa, para un año cuenta y sociedad determinada, tardaba unos 30 minutos.

- Cambiando el loop at gt_bkpf por un all entries , el tiempo ha bajado a 20 minutos

- Cambiando la bseg por la bsis y la bsas, el tiempo ha bajado a menos de un minuto.

bisonye
19/01/09, 10:19:53
Muchas gracias a todos.

el programa, para un año cuenta y sociedad determinada, tardaba unos 30 minutos.

- Cambiando el loop at gt_bkpf por un all entries , el tiempo ha bajado a 20 minutos

- Cambiando la bseg por la bsis y la bsas, el tiempo ha bajado a menos de un minuto.

Estupendo!

Aprovecha para ponerte una medallita, que tal y como están los trabajos puede hacer falta!!

ballan
19/01/09, 13:46:43
Buenas tardes, se que la pregunta esta respondida pero solo queria hacer algun comentario adicional por si a alguien le interesa

Creo que casi todos estaremos deacuerdo en que el INNER JOIN siempre que sea posible es la opcion mas optima pero utilizando FOR ALL ENTRIES se pueden obtener resultados "parecidos"

Si la tabla sobre la que vas a hacer FOR ALL ENTRIES es muy grande se debe partir en trozos (SAP comunmente utiliza fragmentos de 500 registros) y hacer las consultas sobre esos fragmentos

Tambien es recomendable ordenar la tabla por el orden que vayamos a acceder

Ejemplo:

LOOP AT gt_datos

IF sy-tabix MOD 500 = 0.

SORT gt_aux BY campo1 (los campos que vayamos a usar en el where)

SELECT (campos)
APPENDING TABLE tabla
FROM tabla
FOR ALL ENTRIES IN gt_aux
WHERE campo1 = gt_aux-campo1
AND...

CLEAR: gt_aux.
REFRESH: gt_aux.

ELSE.

MOVE_CORRESPONDING gt_datos TO gt_aux
APPEND gt_aux.
CLEAR gt_aux.

ENDIF.

ENDLOOP.

negrogho
20/01/09, 23:31:51
Que tal amigos

tienes razon ballan cuando son registros muy grandes la consulta se hace mas dinamica en pedazos, incluso yo en lugar del FOR ALL ENTRIES utilizo variables tipo rango y realizo la consulta de 1000 en 1000, eso me reduce bastantes los tiempos de consulta

LOOP AT gt_datos

IF contador = 1000.

SELECT (campos)
APPENDING TABLE tabla
FROM tabla
WHERE campo1 IN rango_campo1
AND...

CLEAR: rango_campo1, contador
REFRESH: rango_campo1.

ENDIF.

MOVE 'I' to rango_campo1-sign.
MOVE 'EQ' to rango_campo1-option.
MOVE gt_datos-campo1 to rango_campo1-low.
APPEND rango_campo1.
contador = contador + 1.

ENDLOOP.

Edd_401
21/01/09, 04:28:47
Gracias Por La Correcion, A Lo Mejor Me Falto Aclarar A Que Tablas.

Saludos.