Optimisation - MAJ d'une table

Optimisation - MAJ d'une table - SQL/NoSQL - Programmation

Marsh Posté le 25-07-2008 à 20:13:37    

Bonjour,
Alors tout d'abord je vous explique ce que ma requête fait pour que vous ne soyez pas perdu ^^
J'utilise SQL Server 2005 et ma requête met à jour un champ de la table de la base 1 à partir de la table de la base2.
Ces deux tables sont exactement pareilles hormis les enregistrements qui y sont dedans.
Le problème c'est que la table de la base 2 est extrèmement lourde et fait minimum 50 Millions de ligne
ce qui me donne un temps de traitement trop long pour satisfaire mon boss, en même temps avec cette table, pas évident quoi :/
 
Voici ma requête :

Code :
  1. USE BASE2
  2. UPDATE  Base1.Pack.Prix_Vente
  3. SET BASE1.Prix_Vente.Tarif1 = (SELECT     T1.Tarif1
  4. FROM         Pack.Prix_Vente T1 INNER JOIN BASE1.Pack.Prix_Vente T2 ON T1.Tarif1 = T2.Tarif1
  5. WHERE     (T2.Tarif1 <> T1.Tarif1) AND (T2.Tarif2 = T1.Tarif2) AND
  6.                       (T2.DateDebApplic = T1.DateDebApplic) AND (T2.DateFinApplic = T1.DateFinApplic))
  7. WHERE EXISTS (SELECT     T1.Tarif1
  8. FROM         Pack.Prix_Vente T1 INNER JOIN BASE1.Pack.Prix_Vente T2 ON T1.Tarif1 = T2.Tarif1
  9. WHERE     (T2.Tarif1 <> T1.Tarif1) AND (T2.Tarif2 = T1.Tarif2) AND
  10.                       (T2.DateDebApplic = T1.DateDebApplic) AND (T2.DateFinApplic = T1.DateFinApplic))


 
J'ajoute aussi que le "WHERE EXISTS" est là pour ne pas renvoyer des valeurs "NULL" aux restes des champs qui ne sont pas incluent dans les critères de sélection et que les champs qui devraient être indexer le sont ^^.
 
En espérant que l'on pourra m'aider :)


Message édité par GeGe585 le 25-07-2008 à 20:34:29
Reply

Marsh Posté le 25-07-2008 à 20:13:37   

Reply

Marsh Posté le 27-07-2008 à 22:19:26    

je pige pas trop cette partie en fait...
 
ON T1.Tarif1 = T2.Tarif1
WHERE     (T2.Tarif1 <> T1.Tarif1)
 
tu invalides la clause de jointure dans ton where, c'est normal ? à priori, ça retourne jamais de ligne ça si ?
 
ensuite, quels sont les critères de mise à jour ? genre la table T1, est-ce qu'il est possible de faire un filtre simple qui permet de shooter un grand nombre de lignes sans pour autant perdre les modifications ? je pense notamment aux dates d'application. si les modifications ne peuvent porter que sur des dates relativement récentes, tu peux tenter de partitionner ta table par date de début par exemple et rajouter un filtre "les 6 derniers mois" par exemple afin d'éliminer une grande partie de l'historique

Message cité 1 fois
Message édité par MagicBuzz le 27-07-2008 à 22:20:17
Reply

Marsh Posté le 28-07-2008 à 03:19:26    

MagicBuzz a écrit :


 
ON T1.Tarif1 = T2.Tarif1
WHERE     (T2.Tarif1 <> T1.Tarif1)
 
tu invalides la clause de jointure dans ton where, c'est normal ? à priori, ça retourne jamais de ligne ça si ?


 
Hum... j'y avais même pas fais attention à cette erreur pourtant flagrante.. pas étonnant qu'après 2 heures ça ne retournait aucun résultat !!
 
Les critères de MAJ sont par exemple la mise à jour d'un tarif sur un produit en magasin, ce qui est suivie par la nouvelle "DateDebApplic" ou bien aussi la modification de derniere minutes de la valeur de "DateFinApplic"...errf et logiquement j'ai oublier d'y insérer le champ traitant du libellé du produit ^^'
Mais en y insérant le champ traitant du libellé, ça ne rendrait pas la requête plus longue ?? Sachant qu'on décide d'afficher un nouveau champ.
Je vais tenter de mettre un filtre pour l'année en cours, rien qu'avec cela je pense que ça allègerait grandement la tâche sachant que pour l'année 2008 il y a moins de 10M de lignes :)
 
Sinon comment partitionner une table ? Je vais quand même faire des recherches dessus et tenter de l'appliquer d'ici là.
 
Je testerai tout cela dans la journée et je te ferai part du résultat,
Merci grandement pour m'avoir guidé ^^

Reply

Marsh Posté le 28-07-2008 à 10:05:49    

Non, rajouter des données en retour ne chance pour ainsi dire pas le temps de traîtement (c'est négligeable). C'est surtout le nombre de lignes retournées et analysées qui ralenti.
 
Pour les partitions, tu trouveras de la doc en ligne directement dans SQL Server. Je vais voir ce que je trouve à la limite.

Reply

Marsh Posté le 28-07-2008 à 11:56:53    

Parfois, de simplement recalculer les stats peut suffire à améliorer les performances de ce genre de requêtes. Enfin, c'était valable sour SQL Server <= 2000.
 
Question : tu as dit que la table de la base 2 était extrèmement lourde. Quid des données modifiées ?
Si ta table est lourde, mais que ta requête ne modifie que quelques lignes, ça devrait être rapide !


---------------
Kao ..98 - Uplay (R6S) : kao98.7.62x39 - Origin (BF4, BF1) : kntkao98
Reply

Marsh Posté le 28-07-2008 à 12:45:53    

perso je ne comprend même pas comment ta requête peut marcher, tu updates ta table Base1.Pack.Prix_Vente et tu utilises une 2ème fois cette table dans ton sous-select avec un autre alias, mais sans faire le join avec celle déclarée au niveau de l'update, ou alors c'est parceque c'est du mssql (que je ne connais pas) qui permet ce genre d'entourloupe.
 
autre chose, tarif c'est ton produit ou juste des prix? parceque si ce n'est pas le produit ben y a comme un blème.

Reply

Marsh Posté le 28-07-2008 à 22:28:25    

casimimir a écrit :

tu updates ta table Base1.Pack.Prix_Vente et tu utilises une 2ème fois cette table dans ton sous-select avec un autre alias, mais sans faire le join avec celle déclarée au niveau de l'update, ou alors c'est parceque c'est du mssql (que je ne connais pas) qui permet ce genre d'entourloupe.


 
Tu as raison, vraiment n'importe quoi, ça tourne indéfiniment en fait et je reste comme un con devant l'écran espérant un résultat..
Vraiment désolé pour cette requête toute pourrie... c'est à cause du boulot en fin de semaine..(ne jamais poster du code en cas de fatigue...  :sweat: )
 
Voici le code réorganiser
 

Code :
  1. UPDATE  Base1.Pack.Prix_Vente
  2. SET Tarif1 = (SELECT     T1.Tarif1
  3. FROM         Base2.Pack.Prix_Vente T1
  4. WHERE     (Base1.Pack.Tarif1 <> T1.Tarif1)
  5. AND (Base1.Pack.Tarif2 = T1.Tarif2)
  6. AND (Base1.Pack.Article = T1.Article)
  7. AND (Base1.Pack.DateDebApplic = T1.DateDebApplic)
  8. AND (Base1.Pack.DateFinApplic = T1.DateFinApplic))
  9. WHERE EXISTS (SELECT     T1.Tarif1
  10. FROM         Base2.Pack.Prix_Vente T1
  11. WHERE     (Base1.Pack.Tarif1 <> T1.Tarif1)
  12. AND (Base1.Pack.Tarif2 = T1.Tarif2)
  13. AND (Base1.Pack.Article = T1.Article)
  14. AND (Base1.Pack.DateDebApplic = T1.DateDebApplic)
  15. AND (Base1.Pack.DateFinApplic = T1.DateFinApplic))


 
Avec ceci ma requête s'execute en 8 min, ce qui est pas mal, mais je vais essayer de réduire ce temps au max
 

casimimir a écrit :


autre chose, tarif c'est ton produit ou juste des prix? parceque si ce n'est pas le produit ben y a comme un blème.


 
Voilà, j'ai mis ^^
 

Citation :

Parfois, de simplement recalculer les stats peut suffire à améliorer les performances de ce genre de requêtes. Enfin, c'était valable sour SQL Server <= 2000.


 
J'ai recalculer les stats comme tu me la conseillé, je ne peux pas dire si ça a fait un effet car j'ai appliquer le recal des stats avant le new code, qui lui : renvoits des résultats.
 
@MagicBuzz
 
Je ne pense pas par contre faire un filtre avec les dates car il y a une grosse connerie avec cette table, c'est
qu'il y a des dates de FinApplic sur l'année en cours dont la date de DebApplic est de 2001 (j'ai hérité de la table comme ça).Je vais devoir faire une autre requête qui mettra à jour automatiquement le champ datedebapplic une fois le prix changer, mais bon je verrai cela après ^^;Je tenterai le partitionnement demain
 
En tout cas merci pour vos idées, ça m'avance.


Message édité par GeGe585 le 28-07-2008 à 22:29:06
Reply

Marsh Posté le 29-07-2008 à 16:53:39    

En réalité sur ce genre d'update je ne pense pas que les statistiques auront un impact, car pour les lignes a updater il ne passera pas par un index car ta clause where n'est pas indexable (<> tarif), mais c'est pourtant intéressant de laisser ton where pour ne pas exploser ton redo log (ou son ptit nom en mssql).
Le seul truc a vérifier est que tu attaques ta table de base2 avec un index, et logiquement un index unique qui devrait être mis sur article,DateDebApplic.
 
dans tous les cas, le plan d'exécution est ton ami.
 
un ptit conseil au passage, c'est toujours plus lisible d'aliaser la table que tu updates et d'utiliser cet alias dans ton sous-select, perso je les alias toujours ref (pour référence) et la relecture de code se passe avec moins d'embuche.

Reply

Marsh Posté le 29-07-2008 à 22:25:07    

Pour l'alias de la table dans la clause UPDATE, j'avais déja tenter et bizarrement l'alias n'est pas pris en compte dans la sous requête, c'est pour ça que j'ai été obligé de ne pas mettre d'alias :/
Je vais suivre ton conseil pour les index sur la table de la base 2
Et enfin pour le partitionnement, c'est effectivement très très intéressant, utiliser rarement mais très efficace, je me pencherai sérieusement dessus quand j'aurai le temps finalement ^^'

Reply

Marsh Posté le 06-08-2008 à 14:47:35    

Voici mon code améliorer, j'ai indexer les champs tel que Tarif2, Article, Societe et Marque :

Code :
  1. UPDATE Base1.Pack.Prix_Vente
  2. SET
  3. Tarif1 = T1.Tarif1,
  4. DateDebApplic = T1.DateDebApplic,
  5. DateFinApplic = T1.DateFinApplic
  6. FROM  Base1.Pack.Prix_Vente INNER JOIN
  7. Base2.Pack.Prix_Vente AS T1
  8. ON  Base1.Pack.Prix_Vente.Tarif2 = T1.Tarif2
  9. AND Base1.Pack.Prix_Vente.Article = T1.Article
  10. AND Base1.Pack.Prix_Vente.Societe = T1.Societe
  11. AND Base1.Pack.Prix_Vente.Marque = T1.Marque


 
Si on modifie le tarif, on doit aussi modifier les dates de début et de fin.
Avec cette requête le temps de traitement de la requête est réduit de 50% :)
Voilà... j'espère que ça aidera ceux qui en ont besoin.
 
@ plus et merci à tous pour vos réponses ^^

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed