Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2494 connectés 

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  SQL : Gros problème de lenteur sur un UPDATE

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

SQL : Gros problème de lenteur sur un UPDATE

n°1286345
Arjuna
Aircraft Ident.: F-MBSD
Posté le 18-01-2006 à 10:34:36  profilanswer
 

Bonjour, j'ai une requête "UPDATE" qui tape dans deux tables moyennement volumineuses, et qui met un temps fou (plus de 15 minutes) pour mettre à jour à peine une dizaine de lignes...
 
SGBD : Oracle 8.1.7
 
Structure des tables impactées :
 
PRO :
Table des produits
24424 lignes (3214 avec CODSOC = 2)
Champs :
CODSOC : code société
CODPRO : code produit
...
CODZN15 : champ libre varchar2, contenant une date au format "YYYYMMDD" ou " " si vide (un espace)
 
clé primaire : CODSOC, CODPRO
index que je viens de créer : (pas très utile, parceque un count(*) pour CODSOC = 2 and CODZN15 = ' ' retournait 37 en 0,6 secondes)

Code :
  1. CREATE INDEX WI_PROZN15 ON PRO
  2. (CODSOC, CODZN15)
  3. LOGGING
  4. TABLESPACE IDXGNX1
  5. PCTFREE    10
  6. INITRANS   2
  7. MAXTRANS   255
  8. STORAGE    (
  9.             INITIAL          24K
  10.             NEXT             192K
  11.             MINEXTENTS       1
  12.             MAXEXTENTS       120
  13.             PCTINCREASE      10
  14.             FREELISTS        1
  15.             FREELIST GROUPS  1
  16.             BUFFER_POOL      DEFAULT
  17.            )
  18. NOPARALLEL;


 
EVE :
Table des évènements
187570 lignes (186327 avec CODSOC = 2)
Champs :
CODSOC : code société
ACHVTE : Achat/Vente (flag)
TYPEVE : Type d'évènement (commande, devis, livraison, etc.)
NUMEVE : Numéro d'évènement
...
DATEVE : Date de l'évènement
CODETA : Statut de l'évènement
 
clé primaire : CODSOC, ACHVTE, TYPEVE, NUMEVE
 
EVP :
Table des postes des évènements (lignes)
494172 lignes (484530 avec CODSOC = 2)
Champs :
CODSOC : code société
ACHVTE : Achat/Vente (flag)
TYPEVE : Type d'évènement (commande, devis, livraison, etc.)
NUMEVE : Numéro d'évènement
NUMPOS : Numéro de ligne du poste
...
CODPRO : Code produit
clé primaire : CODSOC, ACHVTE, TYPEVE, NUMEVE, NUMPOS
index utile : CODSOC, ACHVTE, TYPEVE, NUMEVE, CODPRO
 
EVL :
Table des sous-postes des évènements (ventillation datées)
498399 lignes (488706 avec CODSOC = 2)
Champs :
CODSOC : code société
ACHVTE : Achat/Vente (flag)
TYPEVE : Type d'évènement (commande, devis, livraison, etc.)
NUMEVE : Numéro d'évènement
NUMPOS : Numéro de ligne du poste
NUMLIG : Numéro de ligne du sous-poste
...
CODPRO : Code produit
clé primaire : CODSOC, ACHVTE, TYPEVE, NUMEVE, NUMPOS, NUMLIG
index utile : CODSOC, ACHVTE, TYPEVE, NUMEVE, CODPRO
 
 
Ce que doit faire la requête :
 
Mettre à jour le champ CODZN15 de PRO avec la date de la première commande passée sur ce produit
Critères :
CODSOC = 2 (société qui utilise ce champ)
ACHVTE = 'V' (vente)
TYPEVE = 'CDV' (Commande de vente)
CODETA = 'V', 'S', 'I' (Validé, Soldé ou Incident -c'est pas parcequ'on a un problème avec la commande que le produit n'a pas été commandé-)
CODZN15 = ' ' (Si le produit a déjà été commandé avant, ça sert à rien de retrouver la date)
 
La requête originale :

Code :
  1. update pro set codzn15= (select
  2.             nvl(min(eve.dateve),' ')
  3.          from
  4.      evl,eve
  5.    where
  6.    eve.codsoc=2
  7.   and     eve.achvte='V'
  8.   and     eve.typeve='CDV'
  9.   and     (eve.codeta='V' or eve.codeta='S' or eve.codeta='I')
  10.   --
  11.   and evl.codsoc=eve.codsoc
  12.   and evl.achvte=eve.achvte
  13.   and evl.typeve=eve.typeve
  14.   and evl.numeve=eve.numeve
  15.   and evl.codpro=pro.codpro)
  16. where
  17.  codsoc=2 
  18. and  codzn15=' ';


A priori, passer par EVL ne sert à rien, puisque :
1) Un cadencement d'un poste ne peux pas porter sur un produit différent que le poste dont il est issu
2) La société ne fait de toute façon pas de cadancement
3) On récupère la date de la commande, pas celle du cadancement
4) EVL est plus volumineuse que EVP sans apporter plus d'infos dans notre cas
 
J'ai donc modifié la requête :

Code :
  1. update pro set codzn15= (select
  2.             nvl(min(eve.dateve),' ')
  3.          from
  4.      evp,eve
  5.    where
  6.    eve.codsoc=2
  7.   and     eve.achvte='V'
  8.   and     eve.typeve='CDV'
  9.   and     (eve.codeta='V' or eve.codeta='S' or eve.codeta='I')
  10.   --
  11.   and evp.codsoc=eve.codsoc
  12.   and evp.achvte=eve.achvte
  13.   and evp.typeve=eve.typeve
  14.   and evp.numeve=eve.numeve
  15.   and evp.codpro=pro.codpro)
  16. where
  17.  codsoc=2 
  18. and  codzn15=' ';


 
En gros, avec création de l'index et changement de la requête, je suis passé de...
Un temps interminable qui se termine par un rollback à... là même chose.
 
Pourtant, y'a que 37 lignes à mettre à jour !
 
Dans le doute, l'autre jour j'ai profité de la nuit pour rebooter le server, il n'y a donc pas de lock dans la base.
L'outil qui utilise la base, pourtant lourdement consommateur en requêtes, travaille très vite, donc ce n'est pas non plus un problème de performances du serveur.
 
Et là je sèche un peu, je sais pas trop quoi faire pour améliorer la chose.
Je pourrais rajouter une clause WHERE dans ma requête pour ne chercher la date de première commande que pour les produits qui ont été commandés, mais vu qu'il n'y a en tout que 37 lignes (et ça fait une semaine que ça n'a pas tourné !) je doute que ça change quoi que ce soit... :/

mood
Publicité
Posté le 18-01-2006 à 10:34:36  profilanswer
 

n°1286368
Arjuna
Aircraft Ident.: F-MBSD
Posté le 18-01-2006 à 11:00:07  profilanswer
 

Comprends pas...
 

Code :
  1. select count(*)
  2. from eve
  3. where eve.codsoc = 2
  4. and eve.achvte = 'V'
  5. and eve.typeve = 'CDV'
  6. and (eve.codeta = 'V' or eve.codeta = 'S' or eve.codeta = 'I')
  7. => 56799 en 1 seconde
  8. select count(*)
  9. from evp, eve
  10. where eve.codsoc = 2
  11. and eve.achvte = 'V'
  12. and eve.typeve = 'CDV'
  13. and (eve.codeta = 'V' or eve.codeta = 'S' or eve.codeta = 'I')
  14. and evp.codsoc = eve.codsoc
  15. and evp.achvte = eve.achvte
  16. and evp.typeve = eve.typeve
  17. and evp.numeve = eve.numeve
  18. => 145897 en 5 secondes
  19. select count(*)
  20. from pro, evp, eve
  21. where eve.codsoc = 2
  22. and eve.achvte = 'V'
  23. and eve.typeve = 'CDV'
  24. and (eve.codeta = 'V' or eve.codeta = 'S' or eve.codeta = 'I')
  25. and evp.codsoc = eve.codsoc
  26. and evp.achvte = eve.achvte
  27. and evp.typeve = eve.typeve
  28. and evp.numeve = eve.numeve
  29. and pro.codsoc = evp.codsoc
  30. and pro.codpro = evp.codpro
  31. => 145897 en 5 secondes
  32. select count(*)
  33. from pro, evp, eve
  34. where eve.codsoc = 2
  35. and eve.achvte = 'V'
  36. and eve.typeve = 'CDV'
  37. and (eve.codeta = 'V' or eve.codeta = 'S' or eve.codeta = 'I')
  38. and evp.codsoc = eve.codsoc
  39. and evp.achvte = eve.achvte
  40. and evp.typeve = eve.typeve
  41. and evp.numeve = eve.numeve
  42. and pro.codsoc = evp.codsoc
  43. and pro.codpro = evp.codpro
  44. and pro.codzn15 = ' '
  45. => 1 en 5 secondes
  46. select pro.codpro, min(eve.dateve)
  47. from pro, evp, eve
  48. where eve.codsoc = 2
  49. and eve.achvte = 'V'
  50. and eve.typeve = 'CDV'
  51. and (eve.codeta = 'V' or eve.codeta = 'S' or eve.codeta = 'I')
  52. and evp.codsoc = eve.codsoc
  53. and evp.achvte = eve.achvte
  54. and evp.typeve = eve.typeve
  55. and evp.numeve = eve.numeve
  56. and pro.codsoc = evp.codsoc
  57. and pro.codpro = evp.codpro
  58. group by pro.codpro
  59. => 2008 lignes en 6 secondes
  60. select pro.codpro, min(eve.dateve)
  61. from pro, evp, eve
  62. where eve.codsoc = 2
  63. and eve.achvte = 'V'
  64. and eve.typeve = 'CDV'
  65. and (eve.codeta = 'V' or eve.codeta = 'S' or eve.codeta = 'I')
  66. and evp.codsoc = eve.codsoc
  67. and evp.achvte = eve.achvte
  68. and evp.typeve = eve.typeve
  69. and evp.numeve = eve.numeve
  70. and pro.codsoc = evp.codsoc
  71. and pro.codpro = evp.codpro
  72. and pro.codzn15 = ' '
  73. group by pro.codpro
  74. => 1 ligne en 5 secondes


 
Pourtant, l'update dure 1 heure et 6 minutes d'après le log de la procédure (qui ne fait QUE cette requête !)
J'ai jamais eu le courrage d'attendre la fin dans TOAD pour vérifier, mais ça dépasse les 30 minutes.

n°1286404
Arjuna
Aircraft Ident.: F-MBSD
Posté le 18-01-2006 à 11:30:46  profilanswer
 

J'ai relancé un test d'update, ça marche pas mieu... J'attends depuis 30 minutes que TOAD me rende la main pour coller la requête que j'ai testé :D

n°1286423
Arjuna
Aircraft Ident.: F-MBSD
Posté le 18-01-2006 à 11:50:31  profilanswer
 

y'a du mieux :bounce:
 
45 minutes ! :D
 

Code :
  1. update pro set codzn15=    (select
  2.                                nvl(min(eve.dateve),' ')
  3.                          from
  4.                         evp,eve
  5.                    where
  6.                       eve.codsoc=2
  7.                   and     eve.achvte='V'
  8.                   and     eve.typeve='CDV'
  9.                   and     eve.codeta in ('V', 'S', 'I')
  10.                   --
  11.                   and    evp.codsoc=eve.codsoc
  12.                   and    evp.achvte=eve.achvte
  13.                   and    evp.typeve=eve.typeve
  14.                   and    evp.numeve=eve.numeve
  15.                   and    evp.codpro=pro.codpro)
  16.       where
  17.            codsoc=2 
  18.       and     codzn15=' '
  19.   and exists (select null from evp, eve where eve.codsoc = 2 and eve.achvte = 'V' and eve.typeve = 'CDV' and eve.codeta in ('V', 'S', 'I')
  20.            and evp.codsoc = eve.codsoc and evp.achvte = eve.achvte and evp.typeve = eve.typeve and evp.numeve = eve.numeve and evp.codpro = pro.codpro);


 
Comprends pas :sweat:

n°1286455
Arjuna
Aircraft Ident.: F-MBSD
Posté le 18-01-2006 à 12:11:25  profilanswer
 

Code :
  1. select * from pro
  2.       where
  3.            codsoc=2 
  4.       and     codzn15=' '
  5.   and exists (select null from evp, eve where eve.codsoc = 2 and eve.achvte = 'V' and eve.typeve = 'CDV' and eve.codeta in ('V', 'S', 'I')
  6.            and evp.codsoc = eve.codsoc and evp.achvte = eve.achvte and evp.typeve = eve.typeve and evp.numeve = eve.numeve and evp.codpro = pro.codpro);


 
14 minutes... Comprends pas.

n°1286545
Beegee
Posté le 18-01-2006 à 13:47:28  profilanswer
 

t'as essayé de faire ça en PL/SQL plutôt ?
 
BEGIN
  FOR r IN (ton SELECT avec toutes les conditions pour filtrer un maximum)
  LOOP
    UPDATE ...
  END LOOP;
END;
 
D'ailleurs, t'avais pas trouvé une syntaxe plus sympa pour les update, genre UPDATE (SELECT ...) SET ... WHERE EXISTS (...) ?

n°1286560
Arjuna
Aircraft Ident.: F-MBSD
Posté le 18-01-2006 à 13:54:10  profilanswer
 

cf mon avant-dernier post pour la syntaxe "optimisée"
 
c'est clair, je divise le temps par deux... m'enfin bon :/
 
sinon, je préfère ne pas utiliser de PL à cet endroit, afin d'éviter de faire une transaction qui risque de durer longtemps (et foutre le bronx dans la base pendant ce temps).
 
tant pis, je vais laisser la requête telle quelle en attendant d'avoir une révélation :spamafote:
 
elle se lance à 20h30 le soir. Elle emmerde les américains pendant toute la soirée, et après elle a jusqu'à 4h du matin pour tourner, heure à laquelle le serveur stoppe Oracle et l'appli pour faire un backup à froid. Au départ elle était programmée à 3H et du coup à chaquefois elle terminait pas :D
 
chose étonnant cependant : avant, c'était super rapide, et du jour au lendemain, "pouf" !
 
pourtant, ni la requête ni la structure de la base n'a changé ! par contre  les données, oui. étrange...

n°1286581
Beegee
Posté le 18-01-2006 à 14:12:57  profilanswer
 

La base est en RULE ou COST-BASED ?
Peut-être des stats pas à jour ...
 
Donne-nous les EXPLAIN PLANs également ... si les stats sont à la rue, ça doit faire des table scans non voulus :D
 
PS: la solution en PL/SQL devrait prendre quelques secondes puisque ton SELECT sur les 3 tables impliquées met ce temps là !

n°1286601
Arjuna
Aircraft Ident.: F-MBSD
Posté le 18-01-2006 à 14:28:28  profilanswer
 

Tu peux me filer la structure des tables pour le explain plan ? J'ai pas le MDP system, et du coup je ne peux pas utiliser les tables existantes.
 
Sinon, à priori, vu les résultats des select, mes stats ont l'air à jour... :/
 
PS : Ouais, d'accord avec la vitesse du PL. Mais vu que l'update était rapide aussi et qu'il s'est mis d'un coup à mettre des plombes, je ne peux pas partir du principe qu'il va tout le temps durer pas longtemps... Deplus, c'est un bon gros *.BAT des familles, qui lance la requête, et du coup je veux limiter les risques d'erreurs et mélanges de langage (pas pratique de faire de l'injection SQL depuis un fichier .BAT), sinon je vais jamais m'en sortir.
Et pour des raisons de standardisation, je ne veux pas stocker le PL dans la base.


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  SQL : Gros problème de lenteur sur un UPDATE

 

Sujets relatifs
[CSS] Problème de largeur ![SGBD][SQL]Création d'une base de données
Problème de post avec easyphp -> 405 post not allowedrequete SQL
Problème SQL sous ACCESSProblème avec return ... il ne revoie rien quand je le met dans un if
vba excel: problème de compatibilité sur différents postes de travailProblème pour un quiz
problème pour un quiz 
Plus de sujets relatifs à : SQL : Gros problème de lenteur sur un UPDATE


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR