Re: Query performance problem - Mailing list pgsql-general

From Paul Tillotson
Subject Re: Query performance problem
Date
Msg-id 423A2CB1.7030205@shentel.net
Whole thread Raw
In response to Query performance problem  (Phil Daintree <weberp@paradise.net.nz>)
List pgsql-general
Note: If you want to know WHY this takes so long, please tell us how
many times each loop executes and how long each query takes.

Be sure to post an EXPLAIN ANALYZE for each of your queries that you are
running.  This will show what plans the planner is using and how long
they are actually taking.

----------------------

Advice:

Are you running this inside a transaction?  Do so, because if you don't,
then each UPDATE or INSERT or SELECT runs inside its own transaction,
and committing each transaction has overhead associated with it.

This block of code is INSIDE a while loop that loops once for each row
in chartmaster:

        for ($PeriodNo=$CreateFrom;$PeriodNo<=$CreateTo; $PeriodNo++) {

            $sql = 'SELECT accountcode,
                    period,
                    actual + bfwd AS cfwd,
                    budget + bfwdbudget AS cfwdbudget
                FROM chartdetails WHERE period =' . ($PeriodNo  - 1);
            $ChartDetailsCFwd = DB_query($sql,$db);

            while ($myrow = DB_fetch_array($ChartDetailsCFwd)){

                $sql = 'UPDATE chartdetails SET bfwd =' . $myrow['cfwd'] . ',
                                bfwdbudget =' . $myrow['cfwdbudget'] . '
                        WHERE accountcode = ' . $myrow['accountcode'] . '
                        AND period >=' . $PeriodNo;
                $UpdChartDetails = DB_query($sql,$db, '', '', '', false);
                DB_free_result($UpdChartDetails);
            }
            DB_free_result($ChartDetailsCFwd);
        }


It looks like you're updating the same row in chartmaster multiple
times.  In postgres, because of MVCC, this will cause unnecessary table
bloat, as EVERY TIME you update the same row, it will leave behind
another dead tuple that must be reclaimed by VACUUM.  (In other words,
if you update every row row in chartdetails 10 times without VACUUMing,
then this will cause the table to grow 10x.)

As I am still unsure what this code is supposed to do, please tell me:
how many times is each row in chartdetail getting updated?  If it is
getting updated more than once, could you find a way to update it only once?

First, why is this UPDATE statement inside the while loop at all?  It
doesn't look like it references any members of $AccountRow, which is the
variable that governs the WHILE loop that it is within.  Can you take it
out of the while loop and still get the same results?

Second, could you write that update statement to say WHERE period =
$periodno rather than WHERE period >= $period?  If not, why not?

Regards,
Paul Tillotson

Phil Daintree wrote:

>Dear psqlers,
>
>I need your help!
>
>I administer/develop an open source PHP accounting software project (webERP)
>that was originally mysql only. Since Christmas I and another member of the
>team lower cased all the sql and changed some elements of the SQL to allow it
>to use postgres as well. All appears to work beautifully with just a single
>but important exception.....
>
>
>
[snip]

>Can anyone tell me why does the following code chokes ... literally - this
>works almost invisbly under mysql - pg takes more than an hour even on a very
>small 30 record database.
>
>(The table chartmaster is just a list of general ledger accounts accountcode
>and accountdescription. PK = accountcode)
>
>
>    $ChartAccounts = DB_query('SELECT accountcode FROM chartmaster',$db);
>
>    While ($AccountRow = DB_fetch_array($ChartAccounts)){
>
>        for ($PeriodNo=$CreateFrom;$PeriodNo <= $CreateTo;$PeriodNo++) {
>
>            echo '<LI>' . _('Period Number') . ' ' . $PeriodNo . '</LI>';
>
>            // Check if there is an chart details record set up
>            $sql = 'SELECT count(*) FROM chartdetails
>                    WHERE accountcode='.$AccountRow['accountcode'].'
>                    AND period=' . $PeriodNo;
>            $InsChartDetails = DB_query($sql,$db,'','','',false);
>            $CountRows = DB_fetch_row($InsChartDetails);
>            $AccountExistsAlready = $CountRows[0];
>            DB_free_result($InsChartDetails);
>            if(! $AccountExistsAlready) {
>                $sql = 'INSERT INTO chartdetails (accountcode,
>                            period)
>                    VALUES (' . $AccountRow['accountcode'] . ',
>                        ' . $PeriodNo . ')';
>                $InsChartDetails = DB_query($sql,$db);
>                DB_free_result($InsChartDetails);
>            }
>
>        }
>
>    /*Now run through each of the new chartdetail records created for each
>account and update them with the B/Fwd and B/Fwd budget no updates would be
>required where there were previously no chart details set up ie
>FirstPeriodPostedTo > 0 */
>
>        for ($PeriodNo=$CreateFrom;$PeriodNo<=$CreateTo; $PeriodNo++) {
>
>            $sql = 'SELECT accountcode,
>                    period,
>                    actual + bfwd AS cfwd,
>                    budget + bfwdbudget AS cfwdbudget
>                FROM chartdetails WHERE period =' . ($PeriodNo  - 1);
>            $ChartDetailsCFwd = DB_query($sql,$db);
>
>            while ($myrow = DB_fetch_array($ChartDetailsCFwd)){
>
>                $sql = 'UPDATE chartdetails SET bfwd =' . $myrow['cfwd'] . ',
>                                bfwdbudget =' . $myrow['cfwdbudget'] . '
>                        WHERE accountcode = ' . $myrow['accountcode'] . '
>                        AND period >=' . $PeriodNo;
>                $UpdChartDetails = DB_query($sql,$db, '', '', '', false);
>                DB_free_result($UpdChartDetails);
>            }
>            DB_free_result($ChartDetailsCFwd);
>        }
>
>    }
>
>
>
>
[snip]

>I am hoping that someone will be able to see an alternative simpler method or
>suggest a method of indexing the pg tables to optmise the required queries. I
>would appreciate any help here men.
>
>Many thanks in advance ....
>
>
>


pgsql-general by date:

Previous
From: Lonni J Friedman
Date:
Subject: Re: Installing PostgreSQL in Debian
Next
From: Grant McLean
Date:
Subject: Re: Installing PostgreSQL in Debian