[GENERAL] Catching errors inside a LOOP is causing performance issues

Поиск
Список
Период
Сортировка
От Denisa Cirstescu
Тема [GENERAL] Catching errors inside a LOOP is causing performance issues
Дата
Msg-id CY1PR12MB002522DBEFED43017DD56BBAE67A0@CY1PR12MB0025.namprd12.prod.outlook.com
обсуждение исходный текст
Ответы Re: [GENERAL] Catching errors inside a LOOP is causing performance issues  (Denisa Cirstescu <Denisa.Cirstescu@tangoe.com>)
Re: [GENERAL] Catching errors inside a LOOP is causing performance issues  ("David G. Johnston" <david.g.johnston@gmail.com>)
Список pgsql-general

Hi all,

 

I had a function with a performance issue:

 

totalCharge := 0;

FOR myRecord IN ... LOOP

               ......

               IF severalConditionsAreMet THEN

                              BEGIN

                             

                                             SELECT t1.charge INTO STRICT recordCharge

                                             FROM t1

                                             WHERE t1.id = myRecord.id AND otherComplexConditionsHere;

                             

                                             totalCharge := totalCharge + recordCharge;

                             

                                             ...........

                              EXCEPTION

                                             WHEN OTHERS THEN

                                                            NULL;

                              END;

               END IF;

              

END LOOP;

 

The function was being called 232 times (not counting the number of times the code from the FOR was accessed).

The IF from the FOR LOOP ended up being accessed 4466 times and was taking 561 seconds to complete all 4466 iterations.

 

For the particular data set that I had, the IF was always accessed, the SELECT from above never return data and the code was reaching the EXCEPTION branch each and every time.

I have changed the code to:

 

totalCharge := 0;

FOR myRecord IN ... LOOP

               ......

               IF severalConditionsAreMet THEN

              

                              SELECT t1.charge INTO recordCharge

                              FROM t1

                              WHERE t1.id = myRecord.id AND otherComplexConditionsHere;

              

                              IF (recordCharge IS NULL) THEN

                                             CONTINUE;

                              END IF;

                             

                              totalCharge := totalCharge + recordCharge;

              

                              ...........

                             

               END IF;

              

END LOOP;

 

Please note that for the table t1, the t1.charge column has a NOT NULL condition defined on it.

This time, the code from the IF takes 1-2 seconds to complete all 4466 iterations.

 

Basically, all I did was replace the

 

BEGIN

EXCEPTION

….

END;

 

With

 

               IF conditionIsNotMet THEN

                              CONTINUE;        

END IF;

 

Can someone please explain to me why this worked?

What happened behind the scenes?

I suspect that when you catch exceptions inside of a LOOP and the code ends up generating an exception, Postgres can’t use cached plans to optimize that code so it ends up planning the code at each iteration and this causes performance issues.

Is my assumption correct?

 

Thanks a lot,

Denisa Cîrstescu

В списке pgsql-general по дате отправления:

Предыдущее
От: John Britto
Дата:
Сообщение: [GENERAL] WAL Archive command.
Следующее
От: Tomas Vondra
Дата:
Сообщение: Re: [GENERAL] shared_buffers smaller than max_wal_size