Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
Pages : 1
#1 22/04/2020 23:34:41
- bert2713d
- Membre
Lenteur d’exécution d'un Update simple
Bonjour ,
Je débute sur Postgresql . Mon projet est le suivant. J'importe des fichier csv dans une table qui se nomme "eniram". Une fois importé , j'ai environ 29 000 lignes pour 558 colonnes. Il s'agit de relevé temporel de capteurs pression , températures , etc. Après j'utilise grafana pour faire de jolis dashboard.
Mon problème est que j'ai besoin de faire de petits calculs entre les capteurs . Ex : conso = capteur1 - capteur 2. Donc j'ai voulu faire une moulinette en PL . ça marche. Mais c'est hyper long (des heures) et pourtant je travail en local sur mon PC.
J'aurais voulu savoir si cela vient de mon code ou si l'update d'une table est de toute façon très long et qu'il faut mieux le faire en amont sur les différents CSV importé.
Voici mon code, j'ai ici limité la modification à l'insertion de deux colonnes(tag_559 & tag_560) . A partir de deux capteurs je fais juste deux petits calculs que j'UPDATE dans les nouvelles colonnes.
Au début je ne comprenait pas pourquoi les valeurs renvoyés des Select dans la boucle faisaient n'importe quoi , j'ai resolu le problème avec les "order by" (apparemment il garde pas le classement entre deux select).
ALTER TABLE eniram ADD COLUMN tag_559 NUMERIC (20,6);
ALTER TABLE eniram ADD COLUMN tag_560 NUMERIC (20,6);
SELECT addcolum();
CREATE OR REPLACE FUNCTION addcolum () RETURNS VOID
AS $$
DECLARE
I INTEGER;
compteur NUMERIC(20,0);
jour TIMESTAMP;
flowin Numeric(20,6);
flowout Numeric(20,6);
resultat Numeric (20,6);
charge Numeric (20,6);
resultat2 NUMERIC(20,6);
BEGIN
flowin = 0;
flowout=0;
resultat=0;
I=0;
compteur=0;
SELECT COUNT(*) INTO compteur FROM eniram;
FOR I IN 1..compteur
LOOP
SELECT tag_2 INTO jour FROM eniram ORDER BY tag_2 OFFSET I LIMIT 1;
SELECT tag_23 INTO flowin FROM eniram ORDER BY tag_2 OFFSET I LIMIT 1;
SELECT tag_30 INTO flowout FROM eniram ORDER BY tag_2 OFFSET I LIMIT 1;
SELECT tag_220 INTO charge FROM eniram ORDER BY tag_2 OFFSET I LIMIT 1;
resultat = flowin - flowout ;
if charge =0 then resultat2=0; else resultat2= resultat *10 / charge; end if;
UPDATE eniram SET tag_559 = resultat WHERE tag_2 = jour ;
UPDATE eniram SET tag_560 = resultat2 WHERE tag_2 = jour ;
END LOOP;
END;
$$ language plpgsql ;
merci d'avance
et bonne soirée
Bertr2713d
Hors ligne
#2 23/04/2020 09:15:11
- rjuju
- Administrateur
Re : Lenteur d’exécution d'un Update simple
Bonjour,
Ce n'est pas très surprenant. En effet, effectuer ces opérations lignes par ligne est peut être plus simple à appréhender mais côté performance cela ne marche pas du tout. Il vous faut réécrire le traitement non pas en procédure stockée / langage impératif mais avec du SQL, de façon ensembliste.
En gros, un simple "UPDATE ... SET ..." (cf https://www.postgresql.org/docs/current/sql-update.html ). Vous aurez à priori besoin de CASE (https://www.postgresql.org/docs/current/functions-conditional.html#FUNCTIONS-CASE ) pour la gestion de votre "resultat2".
Julien.
https://rjuju.github.io/
Hors ligne
#3 23/04/2020 09:46:43
- bert2713d
- Membre
Re : Lenteur d’exécution d'un Update simple
Donc j'ai fait pour ma première colonne juste un :
UPDATE eniram SET tag_559 = tag_23 - tag_30;
ça marche en 128ms....purée que je suis con, je dois être trop habitué au boucle en c et VB .... je vois pour le CASE....merci beaucoup !
Hors ligne
#4 23/04/2020 13:52:04
- bert2713d
- Membre
Re : Lenteur d’exécution d'un Update simple
Donc juste pour finir la conversation je met ici le bon code :
UPDATE eniram SET tag_559 = tag_23 - tag_30;
UPDATE eniram SET tag_560=CASE WHEN tag_220=0 THEN 0
ELSE (tag_559 *1000) / ((tag_220/100)*11553)
END;
Je suis passé de 6 heures à 2s .... merci encore
Hors ligne
#5 23/04/2020 21:36:08
- gleu
- Administrateur
Re : Lenteur d’exécution d'un Update simple
Alors, autant c'est mieux, autant ça cause un autre problème. Votre premier UPDATE double la taille de la table, et le deuxième immédiatement après la triple. Tout ça parce qu'avec PostgreSQL, un UPDATE, c'est l'équivalent d'un DELETE suivi d'un INSERT. Vous gagneriez à faire les deux UPDATE en même temps, donc :
UPDATE eniram SET
tag_559 = tag_23 - tag_30,
tag_560=CASE WHEN tag_220=0 THEN 0 ELSE ((tag_23 - tag_30) *1000) / ((tag_220/100)*11553) END;
Ça double toujours la taille de la table, mais au moins ça ne la triple pas. Et du coup, ça doit aussi être plus rapide.
Guillaume.
Hors ligne
#6 23/04/2020 22:19:17
- bert2713d
- Membre
Re : Lenteur d’exécution d'un Update simple
compris , merci !
Pour une base quasi complète à 112 000 lignes , moi : + de 6 heures , moi après vos explications 1 minutes , vous 21s ....
ça va être utile car au final je pense rajouté une dizaine de colonnes.
merci encore et bonne soirée
Hors ligne
#7 25/04/2020 21:41:24
- gleu
- Administrateur
Re : Lenteur d’exécution d'un Update simple
Je suppose qu'avant le tag_559, il y avait 558 autres tag_, et vous parlez d'en rajouter. À un moment, vous allez atteindre une limite, PostgreSQL n'acceptant pas un nombre illimité de colonnes (de souvenir, c'est entre 250 et 1600 suivant la taille (et donc le type) des colonnes). Peut-être qu'il serait bon de passer à une colonne de type tableau.
Guillaume.
Hors ligne
Pages : 1