Optimizing this query in PostgreSQL

Viewed 32

I have this query that performs some updates when a record with specific attributes is not already in a master table, and does different updates otherwise. However, this takes a very long time. From what I've checked the long part is not in the 2 initial select statements (select 1 ...), but what comes after that. How can this query be optimized for a better performance?

DO 
$do$ 
BEGIN 
    IF EXISTS (select 1 from {master_table} as mt, {staging_table} as st where
               st.hash = mt.hash and 
               st.type = 'L' and 
               st.id = mt.id and 
               st.first_date = mt.first_date) 
    AND EXISTS (select 1 from {master_table} as mt, {staging_table} as st where 
                st.hash = mt.hash and 
                st.type = 'F' and 
                st.id = mt.id) 
    THEN 
    update {master_table} 
    set last_date = case when chronology.type = 'L' and 
                              chronology.hash = {master_table}.hash and 
                              chronology.id = {master_table}.id and 
                              chronology.first_date = {master_table}.first_date then '9999-12-31'  
                         when chronology.next_last_date is null then last_date 
                         else chronology.next_last_date end, 
        update_number = case when number = '{number}' then null else '{number}' end, 
        out_time = case when chronology.type = 'L' and 
                             chronology.hash = {master_table}.hash and 
                             chronology.id = {master_table}.id and 
                             chronology.first_date = {master_table}.first_date then '9999-12-31' 
                        when chronology.next_type = 'F' then timeline.next_in_time else '9999-12-31' end 
        from ( 
                select 
                    id, 
                    lead(first_date) over (partition by rec_key order by first_date, in_time) as next_last_date, 
                    lead(type) over (partition by rec_key order by first_date, in_time) as next_type, 
                    lead(in_time) over (partition by rec_key order by first_date, in_time) as next_in_time, 
                    hash, 
                    type, 
                    first_date from {staging_table} 
             ) as chronology; 
    ELSE
        update {staging_table} gt 
        set last_date = case when chronology.next_last_date is null then last_date else chronology.next_last_date end, 
            update_number = case when number = '{number}' then null else '{number}' end, 
            out_time = case when chronology.next_type = 'L' then chronology.next_in_time else '9999-12-31' end 
        from ( 
                select 
                    id, 
                    lead(first_date) over (partition by rec_key order by first_date, in_time) as next_last_date, 
                    lead(type) over (partition by rec_key order by first_date, in_time) as next_type, 
                    lead(in_time) over (partition by rec_key order by first_date, in_time) as next_in_time 
                from {staging_table} 
             ) as chronology 
        where gt.id = chronology.id; 
    END IF; 
END 
$do$ 

0 Answers
Related