Optimisation de requête sql [SQL] - SQL/NoSQL - Programmation
Marsh Posté le 14-02-2012 à 11:44:26
C'est de l'Oracle, du MySQL, ... ?
Essayer
UPDATE T1 |
Marsh Posté le 14-02-2012 à 12:03:41
Alors en ce qui concerne ta proposition je l avais déjà essayé avant d utiliser le Where exists, malheureusement j avais la même erreur oracle.
D'ailleurs je n ai pas bien compris pourquoi.
D'ailleur merci pour ta réponse
Marsh Posté le 14-02-2012 à 12:34:15
T1 et T2 ont la même volumétrie ?
PK sont les clés primaires ?
Les index sont bien placés ?
Marsh Posté le 14-02-2012 à 12:38:38
Y'a pas moyen de savoir si y'a pas des verrous intempestifs qui bloquent ta mise à jour ? (y'a bcp de monde qui l'utilise cette BDD ? bcp de transactions ? )
Marsh Posté le 14-02-2012 à 13:43:34
Alors c'était une requête pour donner un exemple.
sinon y a pas de verrous intempestifs, y a pas mal de monde qui utilise la BDD, mnt je selectionne un id sur lequel je suis le seul à travailelr, y a 1.4 millions de lignes, ce qui fait pas mal de ligne en effet .
pour etre plus concrêt si dessous la vrai requête:
/* 1 */ -- cette requête permet de créer une contrepartie ficitif dans ctpr_id pour chaque facilité (relation 1-1)
insert into optima.r_counterparty
select c.RUN_ID,
f.FACILITY_ID c.CTPR_ID,
c.CTPR_NAME,
c.CTPR_TYPE,
c.RESIDENCE_COUNTRY,
c.BUSINESS_COUNTRY,
c.BUSINESS_GROUP,
c.ORIGIN_CTPR_ID,
c.RSQUARED,
c.KMV_PID,
c.DEFAULT_DATE,
c.ORIGIN_FLG,
c.TURNOVER_AMT_EUR,
c.CTI_CTE_FLG,
c.LGD_SENIOR_UNSECURED_RATE,
c.RATING_CODE,
c.RATING_CODE_CAP,
c.MICRO_PTF_CTPR_CODE,
c.REGUL_PTF_IRBA_CTPR_CODE,
c.REGUL_PTF_STD_CTPR_CODE,
c.APP_CLASS_STD,
c.IG_FLG,
c.RATEMAP_CODE,
c.SHAREHOLDING_NATURE_CODE,
c.LOCAL_RATING_CODE,
c.PDM1,
c.PD_MODEL_NAME,
c.BII_CTPR_TYPE,
c.REGUL_PTF_LEXP_CTPR_CODE,
c.ASSET_SIZE_AMT_EUR,
c.ASSET_SIZE_DATE,
c.DEFAULT_RATING_FLG,
c.PDM2,
c.PDM3,
c.PDM4,
c.PDM5
from r_counterparty c, r_facility f
where c.run_id = 11517
and c.run_id=f.run_id
and c.ctpr_id in (select CTPR_ID
from r_facility
where f.run_id = 11517
group by ctpr_id
having count(*) > 1)
and c.ctpr_id=f.ctpr_id
ensuite faut que je fasse un update et c est là ou j utilise le Where exists et ça prend beaucoup de temps, d'ailleurs jusqu a mnt je n ai pas pu arriver à terme de l exécution.
Marsh Posté le 14-02-2012 à 13:55:42
Un EXPLAIN PLAN sur la requete SQL de mise à jour devrait donner qq pistes je pense
Sinon j'en déduis que T2 contient moins de lignes que T1, c'est bien ça ?
Marsh Posté le 14-02-2012 à 14:03:15
justement il y a le même nombre de lignes mais pas le même nombre de champs, donc en faisant l update il y a des champs null dans T1 qu on peut pas mettre en T2 d ou encore la clause where exists.
La j ai changé ma requête pour prendre un champs indéxé, je relance la requête et je te tiens au courant, j espère vraiment que ça plantera pas cette fois ci .
Je t envoie en MP toute la requête
Marsh Posté le 14-02-2012 à 14:04:15
Sinon
UPDATE T1
SET (COL1,COL2,COL3...) = (SELECT COL1, COL2,COL3 FROM T2 WHERE T1.PK = T2.PK)
WHERE T1.PK IN (SELECT PK FROM T2)
Ca ne passerait pas mieux ( Vérifier la syntaxe, ça fait un bail que j'ai pas fait d SQL ), en supposant que j'ai bien compris la manip :
A savoir mettre à jour toutes les lignes de T2, dans T1
?
Marsh Posté le 14-02-2012 à 14:05:58
Heu j'ai pas bien compris là ...
On met à jour de T1 vers T2 ou de T2 vers T1 (en Français, sans se référer à du SQL, please) ?
Marsh Posté le 14-02-2012 à 14:08:39
T'as lancé un SELECT COUNT(PK) FROM T1 et un SELECT COUNT(PK) FROM T2 à tout hasard ?
Marsh Posté le 14-02-2012 à 14:10:54
maalicius a écrit : on met à jour T2 vers T1 |
maalicius a écrit : justement il y a le même nombre de lignes mais pas le même nombre de champs, donc en faisant l update il y a des champs null dans T1 qu on peut pas mettre en T2 d ou encore la clause where exists. |
Donc si j'ai bien compris et que je reformule :
Lors de la mise à jour de T2 vers T1, certains champs de T2 ont des valeurs à NULL et sont rejetées car les colonnes correspondantes dans T1 n'acceptent pas des valeurs à NULL
C'est bien ça, j'ai bien compris ?
Marsh Posté le 14-02-2012 à 14:14:21
je viens de relancer, et je me suis trompé. pas le même nombre de ligne et c est totalement logique car une contrepartie peut avoir plus facility donc
count(facility)=1481322
count(counterparty)=468545
Marsh Posté le 14-02-2012 à 14:15:10
exactement, tu as très bien compris et c'est exactement ça le problème. On peut les forcer à Null mais on ne veut pas le faire.
Marsh Posté le 14-02-2012 à 14:53:01
Ouf, enfin j'ai réussi.
Merci pour tes conseil précieux.
J'ai changé toutes mes requêtes en prenant un champs indéxé, du coup j'ai utilisé le is not null que tu m as mis dans ta réponse, et ça marche à la perfection.
Merci encore pour le temps que tu as pris pour me répondre, et comprendre mon problème
Marsh Posté le 14-02-2012 à 15:03:25
le is null c'est pas moi qui l'ai suggéré, de rien
Et en cas de problèmes de perfs, le EXPLAIN PLAN est vraiment ton ami
Marsh Posté le 14-02-2012 à 15:08:46
en effet, merci à olivthill pour le conseil
merci encore les amis.
Et je vais me rappler de l EXPLAIN PLAN
Excellente après midi à vous
Marsh Posté le 14-02-2012 à 15:39:56
Ca marche pas ca? :
UPDATE T1
SET COL1 = T2.COL1, COL2 = T2.COL2, COL3 = T3.COL3, ...
FROM T1
JOIN T2 ON T1.pk = T2.pk
Marsh Posté le 14-02-2012 à 16:46:02
Merci pour ta réponse Oliii, Par conter pourquoi tu utilise le JOIN?
on veut juste mettre à jours T2 vers T1
Marsh Posté le 14-02-2012 à 16:48:58
Bosser en PS avec un curseur devrai éviter de parcourir les indexes a chaque ligne à cause du exists peut-être....
Code :
|
Dans l'esprit quoi...
Ceci dit, le where exists c'est pas un peu bullshit, parce que a forciori s'il y a eu une jointure entre T1 et T2 c'est que y'a une ligne avec PK dans T1 et dans T2...
Marsh Posté le 14-02-2012 à 16:51:36
maalicius a écrit : Merci pour ta réponse Oliii, Par conter pourquoi tu utilise le JOIN? |
Bah tu fait ça : WHERE T1.PK = T2.PK, ça reviens au même à priori...
Marsh Posté le 14-02-2012 à 17:56:24
Alors je susi d accord avec toi MEI que le where exists c est un peu bullshit, mnt j ai pensé à utiliser pl/SQL et un curseur et je me suis dit qu il peut y avoir plus simple.
Là j'ai refais toutes les requêtes et j'ai remis la clause where dans l update, et miracle ça marche super bien.
Je pense que j'ai opté pour un champs indéxé alors qu'avant c'était pas le cas .
Merci encore pour toutes vos réponses et d'avoir partagé avec moi ce problème qui m'a bloqué pendant deux jours quand même
Marsh Posté le 14-02-2012 à 18:27:12
les optimiseurs de requêtes des SGBDR sont relativement limités, et on peut vite les envoyer aux "fraises" si on y fait pas gaffe
Marsh Posté le 14-02-2012 à 22:57:32
Zzozo a écrit : les optimiseurs de requêtes des SGBDR sont relativement limités, et on peut vite les envoyer aux "fraises" si on y fait pas gaffe |
En fait c'est plutôt l'inverse, ils sont tellement avancés qu'ils peuvent prendre des mauvais choix car les stats sont pas a jour ou pas représentative des données...
Marsh Posté le 15-02-2012 à 09:16:53
rere everybody,
Alors y a une chose dont je suis pas sûr:
imaginons vous avez le cas suivant:
1 ctpr_id peut avoir plusieur facility_id
on prend un exemple: 1 ctpr_id a 10 facility_id
avec la longue requête que j'ai mis ci dessus, elle me permettra de créer 1 ctpr_id_bis dans ctpr_id pour chaqu'une des 10 facility
à la fin il y aura 10 ctpr_id différents pour chacune des 10 facility_id
La question que je me pose est ce que le premier ctpr_id va rester ou va être inclus dans les 10 ctpr_id?
Si je me suis mal exprimé ou vous n avez pas bien compris ma question n'hésitez pas
Marsh Posté le 15-02-2012 à 09:47:29
J'ai trouvé une petite solution mais probablement il y a mieux.
Alors, dans ma base tout se passe par run_id
ce que je vais faire c est faire tousles changements les updates sur mon run_id actuel, ensuite je vais faire une comparaison avec un run_id qui n a pas été touché, ensuite je vais voir les ctpr_id qui sont resté ensuite les delete.
Pensez vous qu il y a une solution plus rapide?
Marsh Posté le 15-02-2012 à 20:40:49
MEI a écrit :
|
Justement, je ne trouve pas ça très avancé, car en dehors de l'exploitation de stats collectées, il y a assez peu d'heuristiques présentes dans ces analyseurs.
Et je suis d'accord que ça s'en ressent quand les stats sont pas suffisamment à jour
Le pb c'est que la collecte de ces stats est pas transparente et a un coût en termes de ressources.
C'est pas la première fois que je vois cette collecte passée en manuel, quand le/les dba y pensent, et surtout que l'utilisation des serveurs le permet.
Enfin bon, rien ne remplace (encore) un humain bien entrainé
Marsh Posté le 16-02-2012 à 08:53:11
Heu... ya 15ans peut etre ... mais la les optimisateurs tiennent en compte beaucoup plus de choses que les stats. Il y a l'etat du server, la charge CPU, la pression mémoire, les dizaines de parametres, les hints et options, sans parler des queries qui font des fois des pages et des pages avec des dizaines de join dans tout les sens.
Ca fait tres longtemps qu'un humain ne sais pas optimiser aussi bien qu'une machine.
Un humain est parfois nécéssaire pour ajouter des indexes (ou en enlever), ce que l'optimisateur ne fais pas evidement, mais en ce qui concerne l'optimisation d'une query en se servant des données et indexes disponible un optimisateur est pratiquement imbatable.
Marsh Posté le 16-02-2012 à 11:24:35
Le probleme peut aussi venir de la taille de ton logfile insufisante et d'une transaction du coup trop importante. Un moyen simple en oracle est de traiter par lots en faisant simplement :
Code :
|
ce qui te permettra de ne traiter "que" les 10000 premieres lignes et faire les MAJ uniquement quand tu as au moins une différence.
A voir si cela change qq chose ou non, tu peux aussi dans un premier temps évaluer les volumes a mettre a jour avec un select count(*) et la meme clause where.
Edit : clause where ecrite trop vite
Marsh Posté le 16-02-2012 à 16:24:31
Oliiii a écrit : Heu... ya 15ans peut etre ... mais la les optimisateurs tiennent en compte beaucoup plus de choses que les stats. Il y a l'etat du server, la charge CPU, la pression mémoire, les dizaines de parametres, les hints et options, sans parler des queries qui font des fois des pages et des pages avec des dizaines de join dans tout les sens. |
Marsh Posté le 16-02-2012 à 16:39:41
Déjà faudrait pas confondre tout.
Les SGBD on plusieurs étapes :
- réécriture de requête
- ordre de jointure
- meilleur chemin d'accès
Déjà pour sur, l'ordre de jointure est rarement optimal, toutes les combinaisons ne sont pas évaluées => une limite haute existe, et dès qu'une combinaison avec une valeur "faible" est trouvé, on ne cherche pas mieux. Pourquoi, c'est simple, on ne peut pas passer un temps infini a faire ce travail assez couteux.
Marsh Posté le 14-02-2012 à 09:49:04
Bonjour à tous,
J'ai un problème de temps d'exécution,j'ai une table avec plusieurs champs et à peu près 1.4 Million de lignes.
je fais un insert ensuite j'update une table, j'utilise la requête suivante :
UPDATE T1
SET (COL1,COL2,COL3...) = (SELECT COL1, COL2,COL3 FROM T2 WHERE T1.PK = T2.PK)
WHERE EXISTS (SELECT 1 FROM T2 WHERE T2.PK=T1.PK)
le problème c est que j'ai laissé la requête tourner toute la nuit mais ce matin je m'apperçois que ça tourne encore, ce qui n est pas normal.
Est ce que vous sauriez s'il y a une possibilité d'optimiser cette requête.
J'ai utilisé le WHERE EXISTS, car sans cette clause, il m'affiche une erreur "il peut pas remplir les champs avec NULL"
Merci d'avance