MUNDOSAP

MUNDOSAP (foro/index.php)
-   Programación ABAP IV (foro/forumdisplay.php?f=4)
-   -   Como optimizo una consulta con "SELECT SINGLE" (foro/showthread.php?t=1841)

dmgman 22/09/06 12:27:16

Como optimizo una consulta con "SELECT SINGLE"
 
Hola a todos,
Me han encargado optimizar un report ya que el tiempo de ejecucion es demasiado elevado.
Tras analizarlo encuentro que casi la mitad de la ejecucion se va en un "SELECT SINGLE" a la tabla BSAS que contiene 5 millones de registros.
Esta es la famosa sentencia:


No llevo mucho tiempo en Sap y no se me ocurre q alternativa podria tomar.
Gracias

conrad10ar 22/09/06 13:04:00

Habría que ver bien como está el programa completo, pero lo primero que haría es cambiar el IN por un EQ.

Espero te sea de ayuda.

maescobarl 22/09/06 14:27:44

create un indice en la tabla o una vista con un indice y listo!!!!

Espero te funcione

Jotabin 22/09/06 14:37:50

Que haya un IN no hace diferencia con un EQ... en definitiva un IN son varios EQs. El problema son los índices.

Para que un SELECT o SELECT SINGLE sea performante, el WHERE tiene que incluir todos los campos de la clave o todos los campos de alguno de los índices de la tabla.

Como dijo maescobarl, podés crearle un nuevo índice a la tabla para mejorar la performance.

Lo más recomendable suele ser buscar la forma de utilizar uno de los índices ya creados para la tabla, o en el mejor de los casos los campos clave, pero como esto no siempre es posible, como última opción podés crearle un nuevo índice que incluya los campos por los que accede tu select.

maescobarl 22/09/06 14:43:09

Hola Jotabin, Gracias por reforzar mi comentario.

Saludos a todos

conrad10ar 22/09/06 14:53:32

Tienes razón, esa es la manera correcta, igualmente prueba en la consulta usar todos EQ y cambiarlos por IN, y la performance baja.

Saludos a todos!:)

maescobarl 22/09/06 15:20:31

Compañeros,

Creo que de lo anterior surge un nuevo tema, el cual yo no estoy muy adentrado... el uso del TRACE (ST05), alguno de ustedes nos puede dar una catedra de como usarlo y saber especificamente que INDICE se esta ocupando al momento de ejecucion???.

Espero sus comentarios

Saludos

jmadera 22/09/06 15:51:39

Abaperos
 
según lei en unos datos que consegui por la internet una de las cosas principales que tenemos que hacer al momento de realizar un select es colocar las ? falsas delante y luegos las verdaderas, ademas creo que lo mejor es tratar de colocar la mayor cantidad de campos claves dentro del where es lo mejor.

Jotabin 22/09/06 18:48:57

Eso de las condiciones falsas por delante no lo conocía, pero sí tengo entendido que cuando la condición para uno de los campos del WHERE es negativa, ese campo no cuenta para el índice; es decir que, para asegurarte de que tu SELECT use un índice [que puede ser la clave principal] no sólo tenés que asegurarte de incluir todos los campos de ese índice, sino que además la condición con la cual los usás tiene que ser positiva.

Jotabin 22/09/06 18:50:07

Ah, y sí... si alguien puede aportar una pequeña explicación o algún manual sobre el uso del TRACE, yo también lo agradecería mucho porque no tengo idea de ese tema.

dmgman 25/09/06 09:00:17

Hola, gracias a todos, por la ayuda.

No se como realizar el indice o no entiendo a que os referis... no llevo mucho tiempo en este mundillo. Me podriais explicar a que os referis con el indice, creo q un ejemplo me vendria de perlas. Gracias

Jotabin 25/09/06 13:01:18

A ver... Supongo que sabés que toda tabla del diccionario ABAP tiene campos clave, ¿cierto?

El motivo principal para que exista esta "propiedad" de los campos que diferencia a los clave de los no clave, es la creación de un índice para los campos clave de la tabla.

¿Que qué es un índice? Es una especie de tablita, mucho más pequeña que la tabla a la cual "indexa", que contiene únicamente los campos clave de la tabla indexada y, por cada clave, un puntero que indica la posición del registro que corresponde a esa clave dentro de la tabla indexada.

O sea que termina siendo algo muy parecido al índice en un libro. Si uno quiere encontrar dónde empieza un determinado capítulo en un libro, es mucho más fácil ir al índice y fijarse el número de página que ir mirando una a una las páginas desde el principio.

Bueno, para la computadora es igual. Si tiene que recorrer la tabla registro a registro para encontrar el valor buscado, el trabajo realizado será mucho mayor que si hace una búsqueda binaria sobre el índice, y desde ahí accede directamente al registro buscado gracias al puntero que le indica dónde está almacenado.

Entonces, cuando un programa recupera datos de una tabla acotando la búsqueda a ciertos valores, la recuperación de datos será muchísimo más veloz si los campos por los que se acota la búsqueda son los campos clave de la tabla, ya que le permitiremos al sistema utilizar el índice creado.

Ahora, resulta que SAP, como toda base de datos decente, te permite crear también otros índices para la tabla aparte del índice principal, el de la clave. De esta manera, uno puede elegir los campos que se le ocurran (sean clave o no) y SAP solito se encarga de indexar la tabla según esos campos, es decir que crea una tablita ordenada por los campos indicados con referencias a la posición de cada registro dentro de la tabla principal. De esta manera, se pueden lograr velocidades de acceso similares a las que se consiguen accediendo por la clave principal de la tabla.

Espero que se haya entendido.

Jotabin 25/09/06 13:03:49

btw, los índices para tablas son creados desde el diccionario de datos [Trx. SE11], con el botón "Índices".
Es bastante intuitivo, pero si llegás a tener algún problema consultá acá e intentaremos ayudarte.

dmgman 25/09/06 16:20:45

Hola a todos.
Si ya he entendido que son los indices, la verdad que pese a haber pasado por ahi 600 veces, no los habia usado hasta ahora...

He estado comentandolo por aqui con los compañeros, y me han dicho que al usarlo, simplemente es necesario que en el select se establezca el mismo orden que existe en uno de sus indices.

Es decir, ej:
si tengo el indice:
yo haria el siguiente select:

LouieBoy 26/09/06 07:17:45

Buenas, perdonad mi igonrancia, pero que ganais haciendo todo esto contra un select single con toda la clave y con la tabla indexada, micro segundos? nano segundos? vale la pena todo esto para ganar tan poco? :eek:

Saludos

LouieBoy

sealons 26/09/06 07:51:37

aupa gente,
La ST05 que tengo en este sistema me aparece en aleman, y no me acuerdo de los nombres en castellano, pero mas o menos a ver si nos entendemos :) . Lo he usado poco, pero se trata de marcar el acceso SQL-Trace en las opciones de la izquierda, viene por defecto. En las de la derecha activar el trace. En otro modo que ya tienes que tener abierto, realizas la ejecucion del programa que quieres analizar. Despues detienes el analisis en las opciones de la derecha, y finalmente examinas los resultados con otra de las opciones.
A mi me pone 'Trace einschalten' en la primera, activar trace; 'Trace ausschalten' en la tercera, interrumpir trace; y 'Trace anzeigen' en la cuarta, mostrar trace; seguro que a ti te viene en castellano.
Al mostrar el trace te aparece la ventanita con tu usuario...y al aceptar ves los accesos y tiempos de la ejecucion que hayas realizado, o de lo que sea que estes realizando en ese momento, para no liarse es mejor tener solo lo que interesa...
no se si te habre ayudado con tanto aleman :rolleyes: , espero que si

saludos,
sealons.

dmgman 26/09/06 07:56:26

Hola a todos,
Al fin he conseguido usar un indice, pero dado que los existentes no tenian la composicion de campos y/o orden que necesitaba, he creado uno propio.
El proceso solo gracias a este indice ha bajado 30 segundos.
Aunque la verdad que creo que no hace mucha gracia que cada uno que necesite un acceso por determinados campos, coja y se cree uno. Vamos que ya me han dicho, que es una buena manera, pero que ya hay mucho indices...

Para los que como yo nos sabiamos de indices, os digo que el orden de campos del indice y de los parametros del select dentro de la sentencia where debe de ser la misma.

Espero q con esto valga, pq trabajar con tablas de BD tan grandes es una odisea hacer que sea eficiente.

Por cierto, he descubierto 2 transacciones q me han comentado q me serian de ayuda, los que se encuentran en las transacciones, ST04 y SM50. Si alguien los conoce, y me pudiera contar como interpretarlas y manejarlas, se lo agradeceria.

ballan 04/10/06 16:40:16

Los indices solo funcionan si se utiliza el operador de igualdad y el orden de las clausulas depende, generalmente es muy optimo poner los campos en el select y en el where en el mismo orden que estan en la tabla pero si hay una clausula que sabemos que es muy restrictiva deberia ir primero en la where, por otro lado la eleccion del indice por parte del motor del sgbd es algo bastante complicado pero hay una manera de "forzar" al select para que vaya por un determinado indice, aqui os dejo un ejemplo

SELECT k~vbeln k~augru k~zsfecins k~zsordser
p~posnr p~matnr p~pstyv p~uepos p~kwmeng
f~vbtyp_n f~rfmng f~erdat f~bwart
INTO TABLE i_informe
FROM vbak AS k
INNER JOIN vbap AS p ON k~vbeln = p~vbeln
LEFT OUTER JOIN vbfa AS f ON p~vbeln = f~vbelv
AND p~posnr = f~posnv
WHERE k~auart IN rg_auart
AND k~zsordser IN s_ordser
%_HINTS
ORACLE 'INDEX ("VBAK" "VBAK~Z01")'.

aqui forzaria al select a ir por el indice Z01 de la tabla vbak

otra forma que el estandar utiliza bastante para optimizar los select es partir los rangos en fragmentos mas pequeños y unir los resultados con select appending

Un saludo

worwa 14/12/06 14:04:18

LA transaccion ST05 se utiliza basicamente por los BASIS para medir las cuotas de las trazas SQL para utilizarla es preferible ingresar al sistema en el idioma ingles (ya que ingrasamos en español, el idioma en el cual se va a cargar es ALEMAN, -no me pregunten por que-) y alli seleccionamos el tipo de traza que queremos evaluar (si es SQL Trace, Enqueue Trace, RFC Trace o Buffer Trace) y se selecciona la opcion de la traza con los parametros que ella pida, entre las que se encuentran:

Activate Trace: Sirve para activar el medidor de la traza para todos los selects de los programas que este corriendo el usuario en curso.

Activate Trace with Filter: Sirve para activar el medidor de la traza para los selects de un programas que este corriendo el usuario en curso, en ese momento, podemos especificar la transacción, el nombre del programa, el usuario, la identificacion del proceso e include y podemos incluir o excluir de acuerdo a lo que necesitemos evaluar.

Deactivate Trace: Desactiva la traza SQL para que despues podamos ver el resultado de la Evaluacion el Display Trace.

Display Trace: Aqui se puede ver el resultado de el desempeño de la traza que decidimos evaluar, podemos especificar una serie de opciones que se nos presentan o simplemente activar con las que ya vienen por defecto.

Enter SQL Statment: Esta opcion evalua una Traza SQL que nosotros introduzcamos en el editor que se nos presenta en la pantalla, recomiendo no usar variables sino valores directamente.

En lo personal solo he utilizado en lo que se refire a los tipos de traza las SQL Trace (que miden las trazas SQL en tiempo de ejecución de un programa, para lo que hago un debugin del programa que contiene la traza a evaluar en un nodo y corro la trancación en otro) y las RFC Trace (que miden - a mi parecer - la conectividad entre las BAPIS y los web dinpro).

Espero haberles ayudado en algo.

P.D.: Todo lo anteriormente dicho lo he sacado de mi propia autoria y experiencia, cualquier cosa pueden contactarme a mi correo .

P.D2.: Voy a ver si puedo Hacer una presentacion de anteriormente narrado y les escribo de nuevo.

Mauricio Hidalgo 14/12/06 16:17:54

Aprovecho de comentar que en algunas querys es visto que le agregan unos HINTS para mejorar la performance.

Por ejemplo originalmente había esta query.

SELECT lednr bzobj kalnr kalka kadky tvers bwvar
kkzma posnr matnr werks typps lstar menge
meeht wrtfw_pos fwaer tpreis peinh pmeht wertn
INTO TABLE t_ckis
FROM ckis
FOR ALL ENTRIES IN t_keko
WHERE lednr = '00'
AND bzobj = t_keko-bzobj
AND kalnr = t_keko-kalnr
AND kalka = t_keko-kalka
AND kadky = t_keko-kadky
AND tvers = t_keko-tvers
AND bwvar = t_keko-bwvar
AND kkzma = t_keko-kkzma.

lentisima en PRD, la dejaron así

SELECT lednr bzobj kalnr kalka kadky tvers bwvar
kkzma posnr matnr werks typps lstar menge
meeht wrtfw_pos fwaer tpreis peinh pmeht wertn
INTO TABLE t_ckis
FROM ckis
FOR ALL ENTRIES IN t_keko
WHERE lednr = '00'
AND bzobj = t_keko-bzobj
AND kalnr = t_keko-kalnr
AND kalka = t_keko-kalka
AND kadky = t_keko-kadky
AND tvers = t_keko-tvers
AND bwvar = t_keko-bwvar
AND kkzma = t_keko-kkzma
%_HINTS DB6 'CONVERT_FAE_TO_CTE'
DB6 'USE_OPTLEVEL 0'.

y la performance de la query mejoró notablemente. Por decir algo
si antes se demorar 17000 mil segundos, habrá quedado en 500 segundos.

como?, ni idea!!, por que no he podido encontrar información acerca de esos HINTS.

dejó la inquietud, haber si alguien pillo en BD nos puede aclarar esto.

saludos a Todos.

sap2006 15/12/06 07:48:54

Hace tiempo lei un manual de optimizacion sql para SAP muy bueno, lo buscaré y lo postearé. A modo de resumen (muchas cosas ya comentadas anteriormente) los pilares se basan en:

*Entrar por el indice. El orden de como esté definido el indice SI
importa.

*Utilizar condiciones positivas.situar la condición que más frecuentemente sea falsa en primer lugar.

*Evitar bucles SELECT anidados. Utilizar la clausula FOR ALL ENTRIES, joins, vistas...

*Evitar condiciones de búsqueda complejas.

*En selects single (solo lectura, en tablas pequeñas y sin muchos movimientos) utilizar la clausula "BYPASSING BUFFER".

En la se30, si vais a TIPS&TRIKS podeis ver ejemplos de rendimiento y evaluar vuestro codigo.

Salu2.


AQUI LO TENEIS: SACADO DEL FORO SAP4.COM.

1.1 Objetivo









El objetivo que se persigue con estas recomendaciones es orientar y concienciar a los desarrolladores de que ABAP presenta un conjunto de instrucciones reducido, pero con muchas opciones o posibilidades de realizar una misma consulta o instrucción.






Es evidente que las mejoras en unos pocos milisegundos no son importantes aisladamente, pero en muchos casos podremos aplicar estas mejoras en bucles o rutinas que se ejecuten cientos de veces, lo que hará que estos milisegundos ahorrados se multipliquen.






Por regla general el rendimiento de los programas ABAP viene determinado en gran parte por la “eficiencia” de sus accesos a las Bases de Datos (BD).






Para entender cómo las sentencias SQL afectan a la ejecución de programas ABAP, es necesario entender la arquitectura del sistema que hay por debajo. Los procesos de trabajo de un servidor de aplicación están “conectados” al servidor de la BD como usuarios (clientes) durante el tiempo que el sistema R/3 está activo. El gestor de la BD (Data Dase Management System - DBMS) realiza la conexión entre usuarios y datos.






Cada sistema de BD utiliza un optimizador cuya tarea es crear el plan de ejecución para las sentencias SQL (por ejemplo determinar entre el uso de un índice en vez de leer en la BD). Hay dos tipos de optimizadores:






Optimizadores basados en la norma: analizan la estructura de una sentencia SQL (las partes SELECT y WHERE sin sus valores) y los índices. Después usa un algoritmo para calcular qué método usar para ejecutar la sentencia.


Optimizadores basados en el coste: usan el procedimiento anterior pero también utilizan tablas de estadísticas. Las tablas de estadísticas contienen los valores más bajos y altos de los campos, o un histograma con la distribución de los datos en la tabla. Este tipo de optimizadores mejoran el tiempo de acceso a las BD, pero tienen la desventaja de que las tablas de estadísticas necesitan actualizarse periódicamente.






(Consultar Anexo 3: “Notas sobre las Tablas de Estadísticas”)






Nota: SAP bajo Oracle permite el uso del optimizador basado en coste a partir de la release 4.x. Anteriormente eran basados en la norma.





1.2 Recomendaciones Generales








1.2.1 Consideraciones SAP- ABAP








No actualizar NUNCA la base de datos directamente mediante funciones no desarrolladas u originales de SAP. Es decir, no utilizar nunca explícitamente las instrucciones INSERT, UPDATE, MODIFY o DELETE sobre tablas estándar de SAP. Deben utilizarse los procedimientos de actualización previstos por SAP como batch-input, direct input o call transaction.






En el caso de tener desarrollos propios que incluyan definición de tablas propias que crecen con el tiempo, tener previsto siempre la posibilidad de realizar un archivado de los datos propios o en su defecto, eliminación de datos obsoletos que no interesa seguir teniendo en el sistema. (Nota: No es aconsejable acceder a datos de transacción sólo con datos maestros –por ejemplo a pedidos de la tabla VBAK sólo con el número de cliente-, ya que siempre cogeremos más registros de los deseados. Conviene usar más campos –por ejemplo la fecha- para limitar el resultado.






En el caso de utilizar programas externos a SAP, como servidores RFC o clientes RFC tener en consideración al posibilidad de realizar balanceo de carga






Tener en cuenta la concurrencia de accesos si se realizan programas para actualizar tablas propias definidas por el cliente mediante la utilización de objetos de bloqueo.






Los accesos a la base de datos deben evitar el realizar un 'Full Table scan' de la misma. La programación de la cláusulas de acceso a la base de datos siempre deben estar basadas en índices, o en casos especiales de conveniencia, realizar una lectura secuencial de la tabla. Pero si se quiere acceder por índice hay que indicar en el predicado de la cláusula todos los campos del índice conocidos por el programa. Por ejemplo: la tabla VBAK definida con los campos: MANDT BELNR POSNR ..., y tiene un índice primario construido así: MANDT, BELNR y POSNR; si en la cláusula WHERE no contiene el campo BELNR, la BD no puede usará el índice adecuadamente.






El conjunto de instrucciones con SQL nativo o EXEC-SQL no es conveniente de forma general ya que:


No utilizan los buffers intermedios de SAP


Pueden hacer la programación dependiente del gestor de base de datos que se utilice.


En ocasiones puede ser la única alternativa en caso de tener que acceder desde un ABAP a una base de datos externa no-SAP, (por ejemplo acceso a una base de datos Oracle en NT mediante ODBC).






Al codificar bucles, diseñarlos de forma que las condiciones que más frecuentemente sean verdaderas ocupen los niveles exteriores del bucle.






Para expresiones o evaluaciones lógicas que incluyan el operador AND, situar la condición que más frecuentemente sea falsa en primer lugar.






Tener identificados de la manera más precisa y operativa posible cuáles son los procesos que no deben ser ejecutados en concurrencia con el online o con los momentos de mayor actividad online en el sistema. A modo de ejemplo normalmente la ejecución de programas que realicen CALL TRANSACTION de forma masiva o lanzamiento de batch-inputs debe estar limitada cuando se procesen de forma concurrente con el on-line.





1.2.2 Normas generales para programación SQL








Basándonos en la arquitectura de los sistemas R/3, existen unas normas básicas y fundamentales que es necesario aplicar en programación ABAP para que los accesos a las BD sean eficientes. Son los siguientes:






Conseguir un conjunto de respuestas pequeño.






Esto reduce: tanto la cantidad de memoria utilizada por el DBMS como la carga de la red cuando se transfieren los datos al servidor de aplicación. Por ejemplo no usar select anidados sino JOINS o VISTAS.






Minimizar la cantidad de datos a transferir






Restringir el número de líneas.


Restringir el número de columnas.


Usar funciones globales (sum, average, minimun, ...) cuando los datos a usar sean sólo para cálculos.


Transferir los datos exactos cuando se cambien líneas de una tabla. Con la sentencia UPDATE para cambiar líneas, se debería usar la cláusula WHERE para especificar las líneas relevantes y la sentencia SET para cambiar sólo las columnas necesarias.






Minimizar el número de transferencias de datos






Conviene reducir la carga de la red y del servidor de la BD minimizando el número de veces que se accede a la BD:


Evitar accesos repetidos.


Evitar bucles SELECT anidados.


Usar Views y Joins.


Evitar sub-preguntas en las cláusulas WHERE y HAVING.


Usar tablas internas en bucles SELECT.


Usar un cursor para leer los datos. Este nuevo método se basa en evitar la cláusula INTO de la sentencia SELECT utilizando un cursor (OPEN CURSOR) y leyendo los datos línea a línea (FETCH NEXT CURSOR). Es necesario abrir un nuevo cursor en cada paso del bucle.






Minimizar el tiempo de búsqueda






Formular condiciones de búsqueda por índices.


Utilizar condiciones positivas (por ejemplo EQ y LIKE) en vez de negativas (NE y NOT LIKE). Evitar el operador NOT.


No chequear por valores nulos (NULL).


No usar parte de un índice: al construir un índice de varias columnas el sistema puede usarlo aunque sólo se especifiquen unas pocas columnas en la condición. La secuencia de las columnas en el índice es importante. Una columna sólo podrá usarse en la consulta por índice si todas las columnas anteriores (en la definición del índice) se han especificado también en la condición de búsqueda.


Evitar condiciones de búsqueda complejas.










Reducir la carga de la BD






Realizar el buffering de tablas sobre el servidor de aplicación.


Tipos de tablas más indicadas:


Tablas que se leen muy frecuentemente,


Tablas que cambian con muy poca frecuencia,


Tablas relativamente pequeñas (pocas líneas, pocas columnas, columnas cortas),


Tablas cuya actualización no es crítica en el tiempo. Por ejemplo tablas de parametrización y tablas de condiciones: AXXX, BXXX, CXXX, etc.


Evitar la lectura repetida de los datos.


Usar Bases de Datos Lógicas.





1.3 Recomendaciones Tips & Tricks por SAP








Estas recomendaciones incluyen ejemplos reales, cuyo tiempo de respuesta puede ser medido que pretenden ilustrar los aspectos comentados en el punto anterior.






Estas recomendaciones están localizables en el sistema mediante:






Herramientas  Workbench ABAP  Test  Análisis Tmpo. Ejecución  Tips & Tricks






Se pretende indicar que existen herramientas en el sistema que nos pueden ayudar en momentos de duda a elegir un algoritmo o conjunto de instrucciones más adecuado que otro. Se extrae una muestra a modo de ejemplo pero la lectura que debe realizarse de este apartado es que esta información debe ser consultada de forma online en caso de dudas o búsqueda de sugerencias en el momento de realizar la programación.









1.3.1 Instrucciones sobre la interfaz SAP-SQL








En una cláusula WHERE, el operador lógico NOT no está soportado por los índices. Por ejemplo:






WHERE fecha >= ‘19990212’ es mejor que


WHERE NOT FECHA <= ‘19990212’






Sentencias SELECT con CHECK. Especificar siempre que sea posible las condiciones de selección en la cláusula WHERE


Con la instrucción SELECT utilizar lista de campos en vez de SELECT * con el fin de disminuir el tráfico en la red.






Obtención de sumatorias, máximos, número de filas, ... Utilizar operadores MAX, COUNT, AVERAGE en la lista de campos en vez de realizarlos por programa. Disminuye el tráfico en la red.






Si se procesan los datos una sola vez, es preferible tratarlos en el bucle SELECT ... ENDSELECT que guardarlos en una tabla interna para posteriormente tratar la tabla interna mediante LOOP.







SELECT mediante vistas. Es conveniente sustituir los selects anidados por el uso de vistas.






SELECT * FROM DD01V


WHERE DOMNAME LIKE 'CHAR%'


AND DDLANGUAGE = SY-LANGU.


ENDSELECT.






es preferible a :






SELECT * FROM DD01L


WHERE DOMNAME LIKE 'CHAR%'


AND AS4LOCAL = 'A'.


SELECT SINGLE * FROM DD01T


WHERE DOMNAME = DD01L-DOMNAME


AND AS4LOCAL = 'A'


AND AS4VERS = DD01L-AS4VERS


AND DDLANGUAGE = SY-LANGU.






Tratamiento con arrays






Inserciones con array y actualizaciones de columnas






INSERT CUSTOMERS FROM TABLE itab.






es preferible a :






LOOP AT TAB.


INSERT INTO CUSTOMERS VALUES TAB.


ENDLOOP.






Utilizar actualizaciones de columna en vez de modificaciones de fila






UPDATE SFLIGHT SET SEATSOCC = SEATSOCC - 1.






es preferible a:






SELECT * FROM SFLIGHT.


SFLIGH T-SEATSOCC = SFLIGHT-SEACSOCC -1.


UPDATE SFLIGHT.


ENDSELECT.






Es preferible usar la sentencia SELECT con opción INTO que utilizar la sentencia APPEND dentro del bucle SELECT ... ENDSELECT









1.3.2 Tratamiento de cadenas de caracteres








Usar los operadores CO, CA, CS, etc, en lugar de programarlos. En strings largos, los tiempos de CPU aumentan considerablemente






No programar las sentencias para truncar strings o concatener, sino utilizar la instrucción SPLIT o CONCATENATE.









1.3.3 Tratamiento de tablas internas








Se recomienda el uso de la instrucción COLLECT a partir de la release 3.0 de SAP para construcción de tablas acumulativas.






Accesos por clave






READ TABLE TAB WITH KEY K = 'X' BINARY SEARCH es preferible a:






MOVE SPACE TO TAB.


TAB-K = 'X'.


READ TABLE TAB BINARY SEARCH.






Intentar siempre acceder a una tabla interna ya ordenada.






READ TABLE WITH KEY BINARY SEARCH. es preferible a:






READ TABLE WITH KEY.






En LOOP de tablas utilizar la cláusula WHERE






LOOP AT TAB WHERE K = KVAL.


.....


ENDLOOP es preferible a:






LOOP AT TAB.


CHECK TAB-K = KVAL.


.....


ENDLOOP.






Construcción de tablas ordenadas






No utilizar la instrucción APPEND itab SORTED BY






Utilizar el procedimiento de: 1º Llenar la tabla, 2º Ordenar la tabla


REFRESH TAB_DEST.


LOOP AT TAB_SRC.


APPEND TAB_SRC TO TAB_DEST.


ENDLOOP.


SORT TAB_DEST BY K






es preferible a:






REFRESH TAB_DEST.


LOOP AT TAB_SRC.


READ TABLE TAB_DEST WTTH KEY K= ....


INSERT TAB_SRC INTO TAB_DEST INDEX SY-INDEX.


ENDLOOP.






Construcción de tabla sin duplicados






Es preferible borrar las entradas duplicadas una vez construida la tabla utilizando el procedimiento de 1º - Llenar la tabla, 2º Ordenar la tabla, 3º Borrar duplicados






REFRESH TAB_DEST.


LOOP AT TAB_SRC


APPEND TAB_SRC TO TAB_DEST.


ENDLOOP


SORT TAB_DEST BY K.


DELETE ADJACENT DUPLICATES FROM TAB_DEST.






es preferible a:






REFRESH TAB_DEST.


LOOP AT TAB_SRC.


READ TABLE TAB_DEST WITH KEY K= TAB_SRC-K.


IF SY-SUBRC <> 0 .


INSERT TAB_SRC INTO TAB_DEST INDEX SY-INDEX.


ENDIF.


ENDLOOP.






Uso de áreas de trabajo evitando instrucciones MOVE






Copia de tablas internas: utilizar asignación directa de variables.






TAB_DEST[ ] = TAB_SRC[ ] es preferible a :






REFRESH TAB_DEST.


LOOP AT TAB_SRC INTO TAB_DEST.


APPEND TAB_DEST.


ENDLOOP.






Comparación de tablas internas: Dos tablas internas son iguales cuando tienen el mismo número de líneas y coinciden una a una.






IF TAB1[ ] = TAB2 [ ]


....


ENDIF.






Es preferible a realizar una barrido secuencial de una tabla e ir comparando con la entrada equivalente en la otra tabla.






Para ordenar tablas internas, especificar los campos sobre los que debe verificarse la ordenación.






SORT ITAB BY FIELD1 FIELD2. es preferible a:






SORT ITAB.










Para averiguar el número de registros en una tabla interna, utilizar la instrucción






DESCRIBE TABLE ITAB LINES C_LINEAS. es preferible a:






LOOP AT ITAB.


C_LINEAS = C_LINEAS + 1.


ENDLOOP.






JOIN de tablas, bucles anidados






Evitar recorridos secuenciales y plantearse accesos por índice en la segunda tabla o tabla más interna del bucle.




Suponiendo: tablas ordenadas, TAB2 contiene sólo entradas que existen en TAB1.






I2 = 1.


LOOP AT TAB1.


LOOP AT TAB2 FROM I2.


IF TAB2-K <> TAB1-K.


I2 = SY-TABIX.


EXIT.


ENDIF.


" ...


ENDLOOP.


ENDLOOP.






es preferible a :






LOOP AT TAB1.


LOOP AT TAB2 WHERE K = TAB1-K.


...


ENDLOOP.


ENDLOOP.






Inserción en una tabla desde otra






APPEND LINES OF TAB_SRC TO TAB_DEST. es preferible a:






LOOP AT TAB_SRC.


APPEND TAB_SRC TO TAB_DEST.


ENDLOOP.






Borrado de líneas.






Uso de índices para


DELETE TAB_DEST FROM 450 TO 550. es preferible a:






DO 101 TIMES.


DELETE TAB_DEST INDEX 450.


ENDDO.






DELETE TAB_DEST WHERE K = KVAL. Es preferible a:






LOOP AT TAB_DEST WHERE K = KVAL


DELETE TAB_DEST


ENDLOOP









1.3.4 Tratamiento de parámetros en rutinas y field-symbols








Especificar el tipo de parámetros en las rutinas:


Si se especifica el tipo de los parámetros formales de las rutinas en el código fuente del programa, el compilador de ABAP/4 puede optimizar mejor el fuente. Además, el riesgo de utilizar secuencias erróneas de parámetros disminuye.






Definir tipo en los field-symbols






Si se especifica el tipo del field-symbol, el compilador puede mejorar el rendimiento del programa.


FIELD-SYMBOLS: TYPE I. Es preferible a:






FIELD-SYMBOLS: .







1.3.5 Manejo de variables y tipos








Utilizar variables de tipo I para campos índices de bucle, no de tipo P.






Si los contenidos de las variables van a ser numéricas, definirlas tipo I.






En las asignaciones utilizar constantes con tipo mejor que literales.






CONSTANTS:


PI TYPE F VALUE '3.1415926535897932'.


DATA:


FLOAT TYPE F.


FLOAT = PI.






es preferible a:






DATA:


FLOAT TYPE F.


FLOAT = '3.1415926535897932'.






En cálculos aritméticos utilizar variables de tipo P.






DATA:


P1 TYPE P VALUE '123456789012345',


P2 TYPE P VALUE '543210987654321',


P1 = P1 + P2.






es preferible a:






DATA:


N1(15) TYPE N VALUE '123456789012345',


N2(15) TYPE N VALUE '543210987654321',


N1 = N1 + N2.






En cálculos aritméticos no mezclar variables de varios tipos a no ser absolutamente necesario, de esta forma evitaremos innecesarias conversiones de tipos.









1.4 Exposición de Sentencias SQL “caras”







1.4.1 Definición








Se definen de esta manera aquellas sentencias que:






Desde el punto de vista del usuario “el reloj de arena aparece en pantalla y permanece ahí un largo tiempo”






Desde el punto de vista del sistema: este tiene que leer muchos bloques de datos bien del buffer (supone una carga para el procesador), o bien del disco duro (lo que supone una sobrecarga para el sistema Input/Output).









1.4.2 Tipos








Para todas las BD y para todas las aplicaciones SAP y no-SAP, las sentencias SQL costosas pueden agotar los recursos del sistema operativo y causar graves problemas de rendimiento del sistema entero.






Existen, básicamente, dos tipos de sentencias SQL llamadas “caras” teniendo en cuenta el consumo de los recursos del sistema:






SENTENCIAS SQL CARAS DE TIPO 1:






Se procesan un gran número de registros pero el rendimiento es bueno.


Método de acceso adecuado


Por ejemplo: SQL Trace: > 10 Fetches por instrucción.






SENTENCIAS SQL CARAS DE TIPO 2:






Se procesa un número pequeño de registros pero hay un gran número de lecturas por registro o un elevado tiempo de respuesta por registro.


La estrategia de búsqueda no es eficiente, el método de acceso no es adecuado.


Por ejemplo:


Area de SQL compartida: > 100 peticiones de buffer por registro


SQL Trace: duración de cada Fetch > 500 ms.






Los datos que se necesitan para analizar sentencias SQL son:






Programas (para saber donde cambiar el código).


Sentencia SQL costosa.


Tabla implicada.


Indice utilizado.









1.4.3 Detección








Los tiempos de espera largos son el resultado del tiempo que emplea la BD en devolver los datos pedidos por R/3 y el que emplea R/3 en devolver la siguiente pantalla al usuario.






¿Cómo detectar las sentencias costosas?






Para encontrar el nombre del report o transacción que usa la sentencia SQL se puede utilizar:






Transacción SM50: Visualización de procesos de trabajo. (A partir de la ver. 4.6B también con la transacción ST04).


Transacción ST03: Reporting de Transacciones, carga de trabajo del sistema. (Ver más adelante el punto 6.2.4 Workload Monitor).






Para encontrar los nombres de las tablas accedidas y la sentencia SQL:






Transacción ST05: “Sql Trace”.


Transacción ST04: Area SQL compartida, Análisis de rendimiento de la BD.


Transacción SM50: Visualización de procesos de trabajo, anotamos el PID del proceso correspondiente y a continuación vamos a la transacción ST04:Monitor de procesos de la BD.






Para encontrar los índices implicados, usar la opción EXPLAIN en:






SQL Trace.


Area SQL compartida.


Monitor de proceso de la BD.






(Ver Anexo 4 “¿De Dónde procede la sentencia SQ?”).









1.4.4 Clasificación








Analizando los dos tipos de sentencias a través de SQL Trace (transacción ST05) apreciamos:






Para el primer tipo el tiempo medio de duración es de < 5 ms por registro o < 100 ms por FETCH. Los datos se transfieren con un rendimiento óptimo.


Para el segundo tipo la duración de un FETCH es > de 500 ms.






Si consultamos el Area SQL compartida (transacción ST04; Menú de análisis detallado; Peticiones SQL) para los dos tipos de sentencias anteriores, encontramos:






Para el tipo 1: < 50 peticiones al buffer por registro. Esta es una relación óptima entre el número de registros procesados y el número de bloques de datos escaneados.


Para el tipo 2: > 50. Esta no es una relación óptima y es consecuencia de una estrategia de búsqueda deficiente.









1.4.5 Soluciones








Programas estándar de SAP:






Solución : Consultar notas del OSS.






SENTENCIAS DEL TIPO 1:






Problema : Demasiados registros a transferir.


Solución : Re-escribir el código ABAP. (Ver apartado 1.4.2 “Normas Generales”).










SENTENCIAS DEL TIPO 2:






Problema 1 : No existen los índices adecuados.


Solución : Cambiar el código: añadir campos conocidos, etc.


Cambiar algún índice existente, en vez de crear uno nuevo.


Crear un índice nuevo (analizar antes el histograma de distribución de


los datos con la transacción DB05).


Quitar un índice (especialmente en versiones 3.x de Oracle con


optimizadores en modo normas).






O






Problema 2 : El Optimizador de la BD NO usa el acceso correcto.


Solución : Chequear la tabla de estadísticas; si la cláusula


WHERE es demasiado compleja, re-escribir el código.

dmgman 15/12/06 09:24:21

Creo que es mas facil y mejor postear directamente la web:

guts11 13/08/07 15:00:13

El Select Single esta dentro de un loop??
De ser asi estaria mejor volcar todo a una tabla interna, de los campos que necesites.
Saludos


tomasm 15/08/07 22:47:19

Una alternativa, que funciona relativamente bien en consonancia con el esfuerzo realizado para conseguirla.

Usar las transacciones SQ01 y SQ02 (Generador de querys de SAP)

Crear la query deseada y fisgar en el código generado.

Que trabaje SAP !!!!

Saludos !!! :D

Atlas 30/01/08 16:53:38

Pues me dijeron una cosa que tal vez podria haber ayudado en su momento.

Se supone (llevo un dia que ya no se que pensar) que para tostar menos la base de datos es mejor en vez de un select single dentro de un loop, un select into for all entries de la tabla del loop y dentro del loop un read a la tabla que llenamos con el for all entreis...

sconoredhot 19/03/08 17:06:14

Tengo el presentimiento de que ese select esta adentro de un loop... no podrias mandar todo el código completo?

DCErick 25/03/08 19:43:59

Orden de Campos en Indice
 
Hola.. ya lei el post y no vi si que comentaran si el campo mandt es obligatorio ponerlo en el select para que tome en cuenta el indice.

Tengo un indice para una tabla z con la siguiente estructura


Y mi select es el siguiente


Como pueden notar yo no estoy poniendo el mandante en la clausala where.

Mi otra duda es si al usar un indice el proceso cuando lo ves desde la sm50 en el campo Acción tiene que cambiar a lectura directa? o seguira quedando como lectura secuencial?

moji87 28/05/13 18:16:08

Yo quiero hacer un select single pero no me sale,tengo este error:
THIS LIST "(ZCLIENTES-NOMBRE,ZCLIENTES-APELLIDOS)"
AFTER "INTO" IS NOT OF THE FORM ABAP [...]OR CONTAINS AN UNDEFINITED FIELD.

y el código es:
REPORT ZCONSULTA.

select single NOMBRE APELLIDOS
INTO (ZCLIENTES-NOMBRE,ZCLIENTES-APELLIDOS)
FROM ZCLIENTES
WHERE IDCLIENTE EQ 1.

Igual me falta hacer la vista pero es muy lioso y nose seguir.
Ayudadme ,por favor.

vanesamacri 28/05/13 19:16:18


Buenas tardes.

El problema radica en que no definiste en memoria el destino de los campos. Podrías hacer esto declarando en el código lo siguiente:

TABLES ZCLIENTES.
En este caso, los datos recuperados se almacenarán en la cabecera generada para la tabla de diccionario.

Como alternativa, también podés declarar un registro (o variables individuales) de tipo que coincida con los datos a recuperar en la consulta.

Saludos.

moji87 29/05/13 06:41:28

Gracias...
 
Buenos días,
Entonces...¿Cómo quedaría el código completo?
Gracias y saludos.:eek:

Saludos.

moji87 29/05/13 06:49:32

1 Adjunto(s)
La tabla se activo pero con warrnings,es decir:
Adjunto el log.

moji87 29/05/13 07:40:25

Ver el contendio de la tabla
 
Bueno,parece que utilizando TABLES ZCLIENTES,funciona.
Sintácticamente es correcto el código,ejecuto y demás,pero no veo los registros creados,el contenido de la tabla.¿Cómo hago esto?¿alguna idea?:eek:
Gracias.

moji87 29/05/13 07:44:49

Transacciones SQ01 y SQ02
 
Vale.Estoy probando con sq01 y sq02:
Con SQ01 me dice : Object can be only created in package of namespace /SAPQUERY.¿Cómo cambio a este paquete?
Con SQ02,parece que necesita unirse a otra tabla.
Necestio más ayuda para crear estas consultas con esas transacciones.

Gracias:D

vanesamacri 29/05/13 11:25:14

Pará... ¿de qué estás hablando? Me da la sensación de que estás consultando acerca de múltiples dudas sin seguir ningún tipo de ordenamiento.

Volvamos a la consulta a la tabla ZCLIENTES. Tu consulta original era por qué no activaba el código y ya se encuentra solucionado. ¿Qué es lo que querés hacer ahora? Nunca lo aclaraste.

jvctaz23 29/05/13 15:09:59



Bueno lo que yo te recomiendo es eliminar todos los select single que estén dentro de loops, realizar la consulta con campos clave a las tablas que requieras fuera del loop para posteriormente solo realizar lecturas a tus tablas internas dentro del loop.

Si este fuera tu caso, yo lo aria de esta forma:

types: begin of ty_bsas,
bukrs type bsas-bukrs,
belnr type bsas-belnr,
gjahr type bsas-gjahr,
end of ty_bsas.

data: tg_bsas type table of ty_bsas,
sg_bsas type ty_bsas.

SELECT bukrs belnr gjahr
INTO table tg_bsas
FROM bsas
for all entries in tablai_bkpf
WHERE bukrs EQ tablai_bkpf-bukrs
AND augdt IN r_budat
AND augbl EQ tablai_bkpf-belnr.

if sy-subrc eq 0.
*Se eliminan todos los registros que sean igual a 'ZI'.
delete tg_bsas where blart eq 'ZI'.

* se procede a realizar el loop a tablai_bkpf.
Loop at tablai_bkpf into sg_bkpf.
* Lectura a tabla interna bsas
read table tg_bsas into sg_bsas with key bukrs = sg_bkpf-bukrs
augdt IN r_budat
augbl = sg_bkpf-belnr.
endloop.
endif.


algo así yo haría, espero y me allá dado a entender. Saludos.

moji87 01/06/13 17:25:23

Indexes
 
Pero...¿para que sirve un índice?¿Dónde se utiliza?¿Dónde se crea?¿Cuales se utilizan?

damiko30 18/06/13 12:35:27

Coding
 
Buen día gente!!!
Les comento, tengo un Query que tiene delimitaciones de dos campos, uno es para fechas, en este necesito generar un código ABAP que no me permita cargar un rango de fecha mayor a 30 días. Se puede lograr esto?
Aguardo respuesta. Desde ya muchas gracias.

Jacobo 20/06/17 11:55:40

pasale la tabla bsas a una tabla interna
y luego haces un read a esa tabla interna para coger bukrs,belnr y gjahr

data: i_bsas type bsas occurs 0 with header line.
data: w_bsas type bsas.

SELECT * INTO TABLE I_bsas FROM bsas.

READ TABLE i_bsas INTO w_BSAS
WITH KEY bukrs = bkpf-bukrs
augdt = r_budat
augbl = bkpf-belnr
blart <> 'ZI'
BINARY SEARCH.

en w_bsas estan los campos


Husos Horarios son GMT. La hora en este momento es 01:32:38.

www.mundosap.com 2006 - Spain
software crm, crm on demand, software call center, crm act, crm solutions, crm gratis, crm web