Question

Je travaille actuellement au déploiement d'un ERP basé sur OFBiz. La base de données utilisée est Oracle 10g Enterprise

L’un des problèmes les plus importants concerne certains problèmes de performances d’Oracle, l’analyse des journaux ofbiz, la requête suivante:

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

est très lent. Nous avons testé l'exécution de la requête sans DISTINCT et cela prend environ 30 secondes. Il y a plus de 4 000 000 registres dans la table. Il existe des index pour le champ PK orderID et presque tous les autres champs

Le PLAN EXPLAIN avec DISTINCT est:

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

et sans le DISTINCT est:

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

des idées sur le réglage de Oracle pour améliorer les performances de ce type de requêtes? Il est très difficile de réécrire la requête car elle est générée automatiquement par ofbiz donc je pense que la solution est sur le réglage de l'oracle

merci d'avance

EDIT: J'ai analysé la requête à l'aide de tkprof, comme suggéré par Rob van Wijk et haffax, et le résultat est le suivant

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

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

Il semble donc que le problème réside dans la "lecture diffuse du fichier de base de données". Avez-vous des idées sur la manière de régler oracle afin de réduire l'attente dans cet événement?

Faites un suivi avec le nouveau résultat tkprof, en fermant cette fois la session:

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

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
********************************************************************************
Était-ce utile?

La solution

Si la différence entre les deux requêtes est importante, ce serait surprenant. Vous mentionnez que la requête sans DISTINCT prend environ 30 secondes. Combien de temps dure la requête avec DISTINCT?

Pouvez-vous afficher le résultat tkprof de la requête avec DISTINCT, après avoir suivi la session avec un & "modifier le contexte du nom de trace 10046 des événements de l'ensemble de sessions", niveau 8 '& "; et déconnecter après la fin de la requête? De cette façon, nous pouvons voir où le temps est réellement passé et s’il attendait quelque chose (& "Temp direct de lecture du chemin &" Peut-être?)

Cordialement, Rob.

Suivi, après la publication du fichier tkprof:

Je vois que vous avez réussi à obtenir la sortie tkprof, mais vous n'avez malheureusement pas déconnecté votre session avant la création du fichier tkprof. Maintenant, le curseur était laissé ouvert et il n’a pas pu écrire de lignes STAT # dans votre fichier de trace. C'est pourquoi vous n'avez pas d'opération source plan / ligne dans votre fichier tkprof. Ce serait bien si vous pouviez répéter le processus si la suggestion ci-dessous se révélait être une foutaise.

Un peu de spéculation de mon côté: je pense que le DISTINCT est presque un no-op parce que vous sélectionnez beaucoup de colonnes. Si cela est vrai, votre prédicat & "WHERE STATUS_ID =" ORDER_COMPLETED "&"; est très sélectif et vous bénéficierez d’un index sur cette colonne. Après avoir créé l'index, assurez-vous de bien l'analyser, même si l'histogramme est activé, si les valeurs des données sont asymétriques. Le résultat final sera un plan différent pour cette requête, en commençant par un INDEX RANGE SCAN, suivi par un TABLE ACCESS BY ROWID, menant à une requête très rapide.

Une fois que vous avez créé un index, vous pouvez procéder à une nouvelle analyse de la table, y compris des histogrammes, à l'aide de cette instruction:

exec dbms_stats.gather_table_stats ([propriétaire], [nom_table], cascade = > true, method_opt = > 'POUR TOUTES LES TAILLES DE COLONNES INDEXÉES')

Cordialement, Rob.

Autres conseils

Puisque vous commandez les résultats selon order_date, il est important que vous ayez un index décroissant sur ce champ. Indiquez également à oracle que vous souhaitez utiliser cet index. Placez le champ <=> en premier dans la requête et utilisez un indice tel que

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

Il ne s'agit pas tellement d'avoir des index, mais plutôt de dire à Oracle de les utiliser. Oracle est très pointilleux sur les indices. Vous obtenez les meilleurs résultats lorsque vous choisissez des index en fonction de vos requêtes les plus importantes. En cas de doute, suivre une requête . De cette façon, vous pouvez voir dans quelle partie de la requête oracle passe le plus de temps et si vos index sont effectivement récupérés ou non. Le traçage est précieux pour lutter contre les problèmes de performances.

ORDER_ID est-il déclaré comme PK à l'aide d'une contrainte PRIMARY KEY? Parce que si c’est le cas, je pense que l’optimiseur reconnaîtra que le DISTINCT est superflu dans cette requête et l’optimisera. Sans contrainte, il ne saura pas que cela est superflu et va donc faire des efforts inutiles et considérables pour & "Du-duper" & "; les résultats.

Essayez de désactiver l'agrégation de hachage:

select /*+ no_use_hash_aggregation*/ distinct ...

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

Lors du dépannage d'applications où je n'ai pas le contrôle du code SQL, je constate que le package dbms_sqltune permet de gagner beaucoup de temps. Voir http://download.oracle.com/docs /cd/B28359_01/appdev.111/b28419/d_sqltun.htm , et oui, malheureusement, vous devriez être autorisé à utiliser ce logiciel.

Ce package contient des procédures permettant d'exécuter une analyse de réglage sur un sql_id spécifique dans le pool partagé ou le référentiel AWR. L'analyse contiendra des recommandations d'indexation si des améliorations supplémentaires doivent être apportées. Plus important encore, l'analyseur peut découvrir un chemin d'accès amélioré qu'il peut implémenter avec ce que Oracle appelle un profil SQL. Il s'agit d'un ensemble d'indices qui seront stockés et utilisés à chaque exécution de cet identifiant sql_id. Cela se produit sans que les astuces soient codées dans l'instruction SQL. Il existe également une option permettant d'effectuer ce que vous pouvez appeler une correspondance floue si votre application génère des valeurs littérales dans l'instruction au lieu de variables de liaison.

Bien sûr, cet outil ne doit pas remplacer la compréhension de l'application et de ses structures de données, mais la lecture du résultat qui détaille le chemin d'exécution d'un meilleur plan (s'il est trouvé) peut être pédagogique.

Oracle accède à la table entière à chaque fois que vous exécutez la requête (TABLE ACCESS (FULL)). Création d'un INDEX sur les colonnes STATUS_ID et ORDER_TYPE_ID

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

aidera beaucoup, en particulier s'il existe plusieurs valeurs différentes de STATUS_ID et ORDER_TYPE_ID dans la table ORDER_HEADER.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top