Pergunta

Atualmente estou trabalhando na implantação de um ERP com base OFBiz O banco de dados a ser utilizado é o Oracle 10g Enterprise

Um dos maiores problemas é alguns problemas de desempenho oráculo, analisando os logs OFBiz, a consulta a seguir:

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

é muito lento. Nós testamos executar a consulta sem a DISTINCT e leva cerca de 30 segundos. Há 4.000.000+ registros na tabela. Há índice para o campo PK orderId e quase todos os outros campos

O EXPLAIN PLAN com DISTINCT é:

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

e sem a DISTINCT é:

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

quaisquer ideias sobre tuning Oracle para melhorar o desempenho deste tipo de consultas? É muito difícil para reescrever a consulta porque é gerado automaticamente pelo OFBiz então eu acho que a solução é de cerca de tuning Oracle

Agradecemos antecipadamente

EDIT: Eu analisei a consulta usando tkprof, como sugerido por Rob van Wijk e haffax, eo resultado é o seguinte

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

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
********************************************************************************

Assim, parece que o problema é o 'db arquivo espalhadas ler', todas as idéias para como sintonizar a Oracle, a fim de reduzir o tempo de espera neste evento?

Seguir-se com o novo resultado tkprof, desta vez fechando a sessão:

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

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
********************************************************************************
Foi útil?

Solução

Se a diferença entre as duas consultas é substancial, que seria surpreendente. Você menciona que a consulta sem DISTINCT leva cerca de 30 segundos. Quanto tempo faz a consulta com o take distintos?

Você pode mostrar a saída tkprof da consulta com o DISTINCT, depois que você traçou a sessão com uma "sessão set eventos alter '10046 traço contexto nome para sempre, nível 8'", e desligar após a consulta terminar? Desta forma, podemos ver onde o tempo realmente está sendo gasto e se ele estava esperando por alguma coisa ( "caminho direto ler temp" talvez?)

Saudações, Rob.


Acompanhamento, após o arquivo tkprof foi postada:

Eu vejo que você conseguiu chegar a saída tkprof, mas infelizmente você não desconectar a sessão antes de criar o arquivo tkprof. Agora, o cursor foi deixado aberto e ele não conseguiu escrever STAT # linhas para o seu arquivo de rastreamento. É por isso que você não tem uma operação de fonte de plano / linha em seu arquivo tkprof. Seria bom se você pode repetir o processo, se a sugestão abaixo acaba por ser lixo.

Um pouco especulação do meu lado: Eu acho que o DISTINCT é quase um não-op porque você está selecionando tantas colunas. Se isso for verdade, então o seu predicado "ONDE STATUS_ID = 'ORDER_COMPLETED'" é muito seletivo e você vai se beneficiar de ter um índice nessa coluna. Depois de criar o índice, certifique-se de analisá-lo corretamente, talvez até mesmo com um histograma sobre se os valores dados estão tortos. O resultado final será um plano diferente para esta consulta, começando com um índice de intervalo SCAN, seguido por um acesso à tabela POR ROWID, levando a uma consulta muito rápida.

Depois de ter criado um índice, você pode ter a mesa re-analisados, incluindo histogramas usando esta declaração:

dbms_stats.gather_table_stats exec ([proprietário], [table_name], cascade => true, METHOD_OPT => 'PARA TODOS INDEXED COLUNAS TAMANHO')

Saudações, Rob.

Outras dicas

Desde que você está resultados de ordenação de acordo com order_date é importante que você tem um índice descendente nesse campo. Informe também o oráculo que você deseja usar este índice. Coloque o campo order_date primeiro na consulta e usar uma sugestão como

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

Não é tanto sobre tendo índices, mas sim em contar oráculo para usá-los. A Oracle é muito exigente sobre índices. Você obtém os melhores resultados quando você escolhe índices de acordo com as suas consultas mais importantes. Em caso de dúvida, traçar um consulta. Desta forma, você pode ver em que parte do oráculo consulta gasta mais tempo e se seus índices são realmente pegou ou não. Rastreamento é inestimável quando lutando problemas de desempenho.

é ORDER_ID declarado como o PK utilizando uma restrição de chave primária? Porque se for eu esperaria que o otimizador de reconhecer que o DISTINCT é supérfluo nesta consulta e otimizá-lo para fora. Sem a restrição, não saberá que é supérfluo e assim vai despender um esforço desnecessário e considerável "de-enganar" os resultados.

Tente desativar a agregação de hash:

select /*+ no_use_hash_aggregation*/ distinct ...

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

Ao solucionar aplicações onde eu não tenho controle do SQL acho que o pacote dbms_sqltune poupa muito tempo. Consulte http://download.oracle.com/docs /cd/B28359_01/appdev.111/b28419/d_sqltun.htm , e sim, infelizmente, você deve ser licenciado para usá-lo.

Existem procedimentos neste pacote para executar uma análise de ajuste contra um sql_id específico na piscina comum ou o repositório AWR. A análise irá conter recomendações de indexação se existem melhorias a serem feitas com índices adicionais. Mais importante, o analisador pode descobrir um caminho de acesso melhorado que ele pode implementar com o que a Oracle chama de perfil SQL - este é um conjunto de sugestões que serão armazenados e utilizados sempre que isso sql_id é executado. Isto acontece sem a necessidade das dicas para ser codificados na instrução SQL, e há também uma opção para fazer o que você pode pensar como correspondência difusa se a aplicação gera valores literais na demonstração em vez de variáveis ??de ligação.

É claro que esta ferramenta não deve ser um substituto para a compreensão da aplicação e é estruturas de dados, mas a leitura através da saída que detalha o caminho de execução de um plano melhor (se encontrado) pode ser educativo.

A Oracle está a aceder a toda a tabela cada vez que você executar a consulta (QUADRO DE ACESSO (FULL)). Criando um índice nas colunas STATUS_ID e ORDER_TYPE_ID

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

vai ajudar muito, especialmente se houver vários valores diferentes de STATUS_ID e ORDER_TYPE_ID na tabela ORDER_HEADER.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top