Pregunta

Actualmente estoy trabajando en la implementación de un ERP basado en OFBiz La base de datos utilizada es Oracle 10g Enterprise

Uno de los mayores problemas son algunos problemas de rendimiento de Oracle, analizando los registros de ofbiz, la siguiente consulta:

SELECT DISTINCT ORDER_ID, ORDER_TYPE_ID, ORDER_NAME, EXTERNAL_ID,
 SALES_CHANNEL_ENUM_ID, ORDER_DATE, ENTRY_DATE, VISIT_ID, STATUS_ID, CREATED_BY, 
 FIRST_ATTEMPT_ORDER_ID, CURRENCY_UOM, SYNC_STATUS_ID, BILLING_ACCOUNT_ID, 
 ORIGIN_FACILITY_ID, WEB_SITE_ID, PRODUCT_STORE_ID, TERMINAL_ID, TRANSACTION_ID, 
 AUTO_ORDER_SHOPPING_LIST_ID, NEEDS_INVENTORY_ISSUANCE, IS_RUSH_ORDER, INTERNAL_CODE, 
 REMAINING_SUB_TOTAL, GRAND_TOTAL, LAST_UPDATED_STAMP, LAST_UPDATED_TX_STAMP, CREATED_STAMP, 
CREATED_TX_STAMP, RECIBIR_BODEGAL, RECEPCIONADA_BODEGAL, FECHA_RECEPCION_BODEGAL FROM 
ERP.ORDER_HEADER WHERE ((STATUS_ID = :v0 OR STATUS_ID = :v1 OR STATUS_ID = :v2) AND 
(ORDER_TYPE_ID = :v3)) ORDER BY ORDER_DATE DESC

es muy lento. Hemos probado ejecutar la consulta sin DISTINCT y tarda unos 30 segundos. Hay 4.000.000+ registros en la tabla. Hay un índice para el campo PK Id. De pedido y casi cualquier otro campo

El PLAN DE EXPLICACIÓN con DISTINCT es:

SELECT STATEMENT () (null)
 SORT (ORDER BY)    (null)
  HASH (UNIQUE) (null)
   TABLE ACCESS (FULL)  ORDER_HEADER

y sin DISTINCT es:

SELECT STATEMENT () (null)
 SORT (ORDER BY)    (null)
  TABLE ACCESS (FULL)   ORDER_HEADER

alguna idea sobre el ajuste de Oracle para mejorar el rendimiento de este tipo de consultas? Es muy difícil reescribir la consulta porque ofbiz la genera automáticamente así que creo que la solución es ajustar el oráculo

gracias de antemano

EDITAR: analicé la consulta usando tkprof, como lo sugirieron Rob van Wijk y haffax, y el resultado es el siguiente

********************************************************************************

SELECT DISTINCT ORDER_ID, ORDER_TYPE_ID, ORDER_NAME, EXTERNAL_ID,
 SALES_CHANNEL_ENUM_ID, ORDER_DATE, ENTRY_DATE, VISIT_ID, STATUS_ID, CREATED_BY, 
 FIRST_ATTEMPT_ORDER_ID, CURRENCY_UOM, SYNC_STATUS_ID, BILLING_ACCOUNT_ID, 
 ORIGIN_FACILITY_ID, WEB_SITE_ID, PRODUCT_STORE_ID, TERMINAL_ID, TRANSACTION_ID, 
 AUTO_ORDER_SHOPPING_LIST_ID, NEEDS_INVENTORY_ISSUANCE, IS_RUSH_ORDER, INTERNAL_CODE, 
 REMAINING_SUB_TOTAL, GRAND_TOTAL, LAST_UPDATED_STAMP, LAST_UPDATED_TX_STAMP, CREATED_STAMP, 
CREATED_TX_STAMP, RECIBIR_BODEGAL, RECEPCIONADA_BODEGAL, FECHA_RECEPCION_BODEGAL FROM 
ERP.ORDER_HEADER WHERE STATUS_ID = 'ORDER_COMPLETED' ORDER BY ORDER_DATE DESC

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      9.10     160.81      66729      65203         37          50
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      9.14     160.83      66729      65203         37          50

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 58  

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  db file scattered read                       8178        0.28        146.55
  direct path write temp                       2200        0.04          4.22
  direct path read temp                          36        0.14          2.01
  SQL*Net more data to client                     3        0.00          0.00
  SQL*Net message from client                     1        3.36          3.36
********************************************************************************

Entonces, parece que el problema es la 'lectura dispersa del archivo db', ¿alguna idea de cómo ajustar Oracle para reducir la espera en este evento?

Siga con el nuevo resultado tkprof, esta vez cerrando la sesión:

********************************************************************************

SELECT DISTINCT ORDER_ID, ORDER_TYPE_ID, ORDER_NAME, EXTERNAL_ID,
 SALES_CHANNEL_ENUM_ID, ORDER_DATE, ENTRY_DATE, VISIT_ID, STATUS_ID, CREATED_BY,
 FIRST_ATTEMPT_ORDER_ID, CURRENCY_UOM, SYNC_STATUS_ID, BILLING_ACCOUNT_ID,
 ORIGIN_FACILITY_ID, WEB_SITE_ID, PRODUCT_STORE_ID, TERMINAL_ID, TRANSACTION_ID,
 AUTO_ORDER_SHOPPING_LIST_ID, NEEDS_INVENTORY_ISSUANCE, IS_RUSH_ORDER, INTERNAL_CODE,
 REMAINING_SUB_TOTAL, GRAND_TOTAL, LAST_UPDATED_STAMP, LAST_UPDATED_TX_STAMP, CREATED_STAMP,
CREATED_TX_STAMP, RECIBIR_BODEGAL, RECEPCIONADA_BODEGAL, FECHA_RECEPCION_BODEGAL FROM
ERP.ORDER_HEADER WHERE STATUS_ID = 'ORDER_COMPLETED' ORDER BY ORDER_DATE DESC

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.01          0          0          0           0
Execute      2      0.00       0.00          0          0          0           0
Fetch        1      8.23      47.66      66576      65203         31          50
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      8.26      47.68      66576      65203         31          50

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 58 

Rows     Row Source Operation
-------  ---------------------------------------------------
     50  SORT ORDER BY (cr=65203 pr=66576 pw=75025 time=47666679 us)
3456659   TABLE ACCESS FULL ORDER_HEADER (cr=65203 pr=65188 pw=0 time=20757300 us)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  db file scattered read                       8179        0.14         34.96
  direct path write temp                       2230        0.00          3.91
  direct path read temp                          52        0.14          0.84
  SQL*Net more data to client                     3        0.00          0.00
  SQL*Net message from client                     1     1510.62       1510.62
********************************************************************************
¿Fue útil?

Solución

Si la diferencia entre las dos consultas es sustancial, eso sería sorprendente. Usted menciona que la consulta sin DISTINCT toma aproximadamente 30 segundos. ¿Cuánto tiempo lleva la consulta con DISTINCT?

¿Puede mostrar la salida tkprof de la consulta con DISTINCT, después de rastrear la sesión con un & "; alterar eventos de conjunto de sesiones '10046 rastrear contexto de nombre para siempre, nivel 8' &"; y desconectar después de que la consulta haya terminado? De esta manera podemos ver dónde se está gastando el tiempo y si estaba esperando algo (& "; Ruta directa de lectura temp &"; ¿Tal vez?)

Saludos, Rob.


Seguimiento, después de que se publique el archivo tkprof:

Veo que logró obtener la salida de tkprof, pero desafortunadamente no desconectó su sesión antes de crear el archivo tkprof. Ahora, el cursor se dejó abierto y no pudo escribir líneas STAT # en su archivo de rastreo. Es por eso que no tiene una operación de origen de plan / fila en su archivo tkprof. Sería bueno si puede repetir el proceso, si la sugerencia a continuación resulta ser basura.

Un poco de especulación de mi parte: creo que DISTINCT es casi un no-op porque estás seleccionando tantas columnas. Si esto es cierto, entonces su predicado & Quot; WHERE STATUS_ID = 'ORDER_COMPLETED' & Quot; es muy selectivo y se beneficiará de tener un índice en esta columna. Después de crear el índice, asegúrese de analizarlo correctamente, tal vez incluso con un histograma si los valores de los datos están sesgados. El resultado final será un plan diferente para esta consulta, comenzando con un ESCANEO DE RANGO DE ÍNDICE, seguido de un ACCESO A LA TABLA POR ROWID, lo que lleva a una consulta muy rápida.

Después de crear un índice, puede volver a analizar la tabla, incluidos los histogramas con esta instrucción:

exec dbms_stats.gather_table_stats ([propietario], [nombre_tabla], cascada = > verdadero, método_opt = > 'PARA TODO EL TAMAÑO DE LAS COLUMNAS INDEXADAS')

Saludos, Rob.

Otros consejos

Dado que está ordenando resultados de acuerdo con order_date es importante que tenga un índice descendente en ese campo. También dígale a Oracle que desea usar este índice. Coloque el campo <=> primero en la consulta y use una pista como

SELECT /*+ index(HEADERS IDX_ORDER_DATE_DESC) */ ... 
FROM ERP.ORDER_HEADER HEADERS
WHERE ...
ORDER BY ORDER_DATE DESC

No se trata tanto de tener índices, sino de decirle a Oracle que los use. Oracle es muy exigente con los índices. Obtiene los mejores resultados cuando elige índices de acuerdo con sus consultas más importantes. En caso de duda, rastrea una consulta . De esta manera, puede ver en qué parte del oráculo de consulta pasa la mayor parte del tiempo y si sus índices se seleccionan o no. El rastreo es invaluable cuando se lucha contra problemas de rendimiento.

¿ORDER_ID se declara como PK usando una restricción PRIMARY KEY? Porque si es así, esperaría que el optimizador reconozca que DISTINCT es superfluo en esta consulta y lo optimice. Sin la restricción, no sabrá que es superfluo y, por lo tanto, gastará un esfuerzo innecesario y considerable en & Quot; desduplicación & Quot; los resultados.

Intente deshabilitar la agregación de hash:

select /*+ no_use_hash_aggregation*/ distinct ...

http://oracle-randolf.blogspot.com/2011/ 01 / hash-aggregation.html

Cuando soluciono problemas de aplicaciones donde no tengo control de SQL, encuentro que el paquete dbms_sqltune ahorra mucho tiempo. Consulte http://download.oracle.com/docs /cd/B28359_01/appdev.111/b28419/d_sqltun.htm , y sí, desafortunadamente debería tener licencia para usarlo.

Hay procedimientos en este paquete para ejecutar un análisis de ajuste contra un sql_id específico en el grupo compartido o el repositorio de AWR. El análisis contendrá recomendaciones de indexación si hay que realizar mejoras con índices adicionales. Más importante aún, el analizador puede descubrir una ruta de acceso mejorada que puede implementar con lo que Oracle llama un Perfil SQL: este es un conjunto de sugerencias que se almacenarán y utilizarán cada vez que se ejecute este sql_id. Esto sucede sin requerir que las sugerencias se codifiquen en la declaración SQL, y también hay una opción para hacer lo que puede pensar como coincidencia difusa si su aplicación genera valores literales en la declaración en lugar de variables de enlace.

Por supuesto, esta herramienta no debería ser un sustituto para comprender la aplicación y sus estructuras de datos, pero leer el resultado que detalla la ruta de ejecución de un plan mejor (si se encuentra) puede ser educativo.

Oracle está accediendo a la tabla completa cada vez que ejecuta la consulta (TABLE ACCESS (FULL)). Crear un ÍNDICE en las columnas STATUS_ID y ORDER_TYPE_ID

CREATE INDEX ERP.ORDER_HEADER_I1 ON ERP.ORDER_HEADER ( STATUS_ID, ORDER_TYPE_ID );

ayudará mucho, especialmente si hay varios valores diferentes de STATUS_ID y ORDER_TYPE_ID en la tabla ORDER_HEADER.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top