Vous n'êtes pas identifié(e).

#1 08/07/2009 11:46:38

rbidocho
Membre

Mise à jour d'une "grosse" table

Bonjour,

j'ai une table aaa qui contient quelques 25 millions de lignes.
je voudrais faire un update de toutes les valeurs d'une colonne (f) via une opération avec des valeurs qui sont issues de 2 tables dont l'une est celle que je veux mettre à jour.

mais déjà quand je fais la "simple" requête suivante :

SELECT 
  aaa.e/bbb.a as f
FROM 
  public.bbb, 
  public.aaa
WHERE 
  bbb.c = aaa.c AND
  bbb.s = aaa.s AND
  bbb.r = aaa.r AND
  bbb.n = aaa.n;

pgadmin me réponds :

out of memory for query result

********** Erreur **********

la table aaa contient :
1 pk
2 fk
2 index

donc voici ce que je compte faire :

ALTER TABLE aaa DROP CONSTRAINT aaa_pkey;
ALTER TABLE aaa DROP CONSTRAINT aaa_p_fkey;
ALTER TABLE aaa DROP CONSTRAINT aaa_c_fkey;
ALTER TABLE aaa DROP CONSTRAINT aaa_c_key;
DROP INDEX ind_fk_bbb;
DROP INDEX ind_fk_u_1;

UPDATE bbb
INNER JOIN aaa 
ON (bbb.n = aaa.n) 
AND (bbb.r = aaa.r) 
AND (bbb.s = aaa.s) 
AND (bbb.c = aaa.c) 
SET aaa.f = aaa.e/bbb.a;

ALTER TABLE aaa
  ADD CONSTRAINT aaa_pkey PRIMARY KEY(c, s, r, n, p);
ALTER TABLE aaa
  ADD CONSTRAINT aaa_p_fkey FOREIGN KEY (p)
      REFERENCES u (p) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION;
ALTER TABLE aaa
  ADD CONSTRAINT aaa_c_fkey FOREIGN KEY (c, s, r, n)
      REFERENCES bbb (c, s, r, n) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION;
ALTER TABLE aaa
  ADD CONSTRAINT aaa_c_key UNIQUE(c, s, r, n, p);
CREATE INDEX ind_fk_bbb
  ON aaa
  USING btree
  (c, s, r, n);
CREATE INDEX ind_fk_u_1
  ON aaa
  USING btree
  (p);

Est ce que cela ne va pas planter en plein milieu ???
Ou peut on faire ce genre de maj par paquet ???

merci de vos contributions

RB

ps : config -->
postgresql 8.3.7
windows server 2003 r2
dell server pe2950
Intel Xeon CPU E5310 @ 1.60GHz
8 Go de Ram

Hors ligne

#2 08/07/2009 16:08:05

Marc Cousin
Membre

Re : Mise à jour d'une "grosse" table

Le out of memory for query result ne doit pas provenir de postgresql, mais du client, qui n'arrive pas à stocker le résultat.

La requête en dessous n'a aucune raison de planter...


Marc.

Hors ligne

#3 08/07/2009 20:27:28

gleu
Administrateur

Re : Mise à jour d'une "grosse" table

Et pour répondre aux autres points...

UPDATE bbb
INNER JOIN aaa
ON (bbb.n = aaa.n)
AND (bbb.r = aaa.r)
AND (bbb.s = aaa.s)
AND (bbb.c = aaa.c)
SET aaa.f = aaa.e/bbb.a;

J'ai de très gros doutes sur la bonne syntaxe de cette requête. À mon avis, elle ne passera pas à cause du INNER JOIN. De plus, vous faites un "UPDATE bbb" mais c'est une colonne de aaa que vous mettez à jour. Bref, une construction très bizarre. J'aurais tendance à réécrire votre requête ainsi :

UPDATE aaa
SET aaa.f = aaa.e/bbb.a
FROM bbb
WHERE (bbb.n = aaa.n) 
AND (bbb.r = aaa.r) 
AND (bbb.s = aaa.s) 
AND (bbb.c = aaa.c);

ET je suppose du coup que vous n'avez aucune colonne bbb.a à 0, car sinon c'est une division par zéro, donc un échec de mise à jour, donc la requête entière est annulée.

Est ce que cela ne va pas planter en plein milieu ???

Si elle "plante" quelque soit la raison, cela fera un ROLLBACK des modifications déjà effectuées.

Ou peut on faire ce genre de maj par paquet ???

Oui, c'est possible, mais la façon de le faire dépend de la disponibilité d'une clé primaire ou d'une clé unique.


Guillaume.

Hors ligne

#4 09/07/2009 09:51:11

rbidocho
Membre

Re : Mise à jour d'une "grosse" table

Bonjour,

merci pour ces éclaircissements.

il est vrai que ma requêtes était fausse et je m'en suis rendu compte.
de plus pour essayer d'alléger le problème j'ai fais la requête suivante plusieurs milliers de fois d'affiler

UPDATE aaa as yy 
SET fe=xx.ef
FROM 
	(SELECT  em.c, em.s, em.r, em.n, em.p, em.e, em.fe, em.e/ac.a as ef 
	FROM bbb as ac, aaa as em 
	WHERE ac.c = em.c AND 
		  ac.s = em.s AND 
		  ac.r = em.r AND 
		  ac.n = em.n AND 
		  ac.c='01001') as xx 
WHERE xx.c = yy.c AND 
	  xx.s = yy.s AND 
	  xx.r = yy.r AND 
	  xx.n = yy.n AND 
	  xx.p = yy.p AND 
	  xx.c='01001';
COMMIT;

en changeant à chaque fois le '01001' par les valeurs successives possibles (36590 valeurs possibles).

mais cela à planter quand même au bout de la 10466 ème requête avec un code d'erreur :

ERROR:  out of memory
DETAIL:  Failed on request of size 1048576.

en regardant de plus près, il est vrai que j'ai des valeurs de ac.a qui sont égales à 0 mais elles n'ont pas ac.c, ac.s, ac.r, ac.n en lien dans la table à mettre à jour. Donc normalement, je n'ai jamais la division par 0.

le fait d'avoir mis COMMIT fait que la table à été mis à jour au mois pour les 10465 premières requêtes (i.e. valeurs de em.c ou ac.c)

Si vous avez des idées sur l'erreur précédemment citées !!!

Merci

RB

Hors ligne

#5 09/07/2009 10:59:57

rbidocho
Membre

Re : Mise à jour d'une "grosse" table

rebonjour,

l'erreur viendrait de pgadmin qui ne supporte pas de réaliser quelques 36600 requêtes !!!

j'ai juste effectué ces requêtes en 3 fois.

merci encore de vos aides

RB

Hors ligne

#6 09/07/2009 22:44:17

gleu
Administrateur

Re : Mise à jour d'une "grosse" table

l'erreur viendrait de pgadmin qui ne supporte pas de réaliser quelques 36600 requêtes !!!

Pas très étonnant, il n'est pas vraiment fait pour ça.


Guillaume.

Hors ligne

Pied de page des forums