2017-02-08 4 views
0

У меня есть 61 миллион уникальных писем со статусами. Это письмо необходимо дедуплицировать с логикой по статусу.Как оптимизировать процедуру postgresql

Я пишу хранимую процедуру, но эта процедура длится долго.

Как я могу оптимизировать время выполнения этой процедуры?

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

'Как я могу оптимизировать время выполнения этой процедуры? '** ** ** не используя процедуру с курсором/контуром. Вместо этого вы можете использовать два отдельных оператора SQL (может быть, склеены при помощи цепочки CTE) – wildplasser

ответ

4

Как оптимизировать время выполнения этой процедуры?

Не делайте этого с петлей.

Выполнение обработки по строкам (также известный как «медленный медленный») почти всегда намного медленнее, чем массовые изменения, когда один оператор обрабатывает множество строк «за один раз».

Изменение состояния легко может быть сделано с помощью одного оператора:

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

Копирование строк можно выполнить, используя цепочку 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;