2017-02-08 1 views
0

J'ai 61 millions d'e-mails non uniques avec des statuts. Ces e-mails doivent être dédoublonnés avec la logique par statut.Comment optimiser la procédure postgresql

J'écris une procédure stockée, mais cette procédure dure trop longtemps.

Comment puis-je optimiser le temps d'exécution de cette procédure?

CREATE OR REPLACE FUNCTION public.load_oxy_emails() RETURNS boolean AS $$ 

DECLARE 
     row record; 
     rec record; 
     new_id int; 
BEGIN 
     FOR row IN SELECT * FROM oxy_email ORDER BY id LOOP 
       SELECT * INTO rec FROM oxy_emails_clean WHERE email = row.email; 
       IF rec IS NOT NULL THEN 
         IF row.status = 3 THEN 
           UPDATE oxy_emails_clean SET status = 3 WHERE id = rec.id; 
         END IF; 
       ELSE 
         INSERT INTO oxy_emails_clean(id, email, status) VALUES(nextval('oxy_emails_clean_id_seq'), row.email, row.status); 
         SELECT currval('oxy_emails_clean_id_seq') INTO new_id; 
         INSERT INTO oxy_emails_clean_websites_relation(oxy_emails_clean_id, website_id) VALUES(new_id, row.website_id); 
       END IF; 
     END LOOP; 
     RETURN true; 
END; 
$$ 
LANGUAGE 'plpgsql'; 
+1

'Comment puis-je optimiser le temps d'exécution de cette procédure? Par ** pas ** en utilisant une procédure avec un curseur/boucle. Au lieu de cela, vous pouvez utiliser deux instructions SQL séparées (peut-être collées ensemble par un CTE chaîné) – wildplasser

Répondre

4

Comment puis-je optimiser le temps d'exécution de cette procédure?

Ne le faites pas avec une boucle. Effectuer un traitement ligne par ligne (également appelé «slow-by-slow») est presque toujours beaucoup plus lent que d'effectuer des modifications groupées lorsqu'une seule instruction traite un grand nombre de lignes «en une seule fois».

Le changement de statut peut facilement être fait en utilisant une seule instruction:

update oxy_emails_clean oec 
    SET status = 3 
from oxy_email oe 
where oe.id = oec.id 
    and oe.status = 3; 

La copie des lignes peut être fait en utilisant une chaîne de CTEs:

with to_copy as (
    select * 
    from oxy_email 
    where status <> 3 --<< all those that have a different status 
), clean_inserted as (
    INSERT INTO oxy_emails_clean (id, email, status) 
    select nextval('oxy_emails_clean_id_seq'), email, status 
    from to_copy 
    returning id; 
) 
insert oxy_emails_clean_websites_relation (oxy_emails_clean_id, website_id) 
select ci.id, tc.website_id 
from clean_inserted ci 
    join to_copy tc on tc.id = ci.id;