Search Postgresql Archives

Re: out of memory for query result

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks, everyone. I got it to work! Here is my solution hoping it is useful to the next programmer.

PROBLEM: Perl DBI for Postgres does not implement cursors. All query results are cached in memory. For very large result sets, this give the "out of memory for query result" message.

The prepare(select_statement)/execute(@parms) did not open a cursor as I had thought. It must be explicitly coded. This technique is only applicable for processing large result sets that you do not want cached completely in memory. It may not work for nested cursors?

SOLUTION: Run raw "DECLARE CURSOR" and "FETCH nnn FROM cursor" commands to extract your data.
* Connect with AutoCommit=>0 to enable transactions
* prepare/execute DECLARE cursorname CURSOR FOR select...
  ? Parameters to the SQL are specified here.
* Loop
  * prepare/execute FETCH nnn FROM cursor_name,
    which buffers only the next 'nnn' rows from the cursor
    use a large enough number to decrease server/client overhead
    and small enough to co-exist with other apps/threads.
  * Loop
    * fetchrow_hashref until undef (end of current FETCH set)
    * do something wonderful with the row
* prepare/execute Close Cursor

EXAMPLE: This may not be the cleanest code, but works!

#!/usr/local/bin/perl -w
use strict;
use DBI;

my $dbName='allen';
my $host='localhost';
my $dbUser=$dbName;
my $dbPassword='';

my $dbh = DBI->connect("DBI:Pg:dbname=$dbName;host=$host", $dbUser, $dbPassword,
        { RaiseError => 0, AutoCommit => 0, PrintError => 1 })
        or die "Can't connect to db\n";

loopCursor(
  sub
  {
    my ($row) = @_;
    print "$row->{name}\n";
  },
  "SELECT name from population where ssn>=?",1
);
$dbh->commit();
$dbh->disconnect();
exit;

my $csrnum=0;
sub loopCursor
{
  my ($proc, $sql, @parms) = @_;
  my ($sth, $row);
  ++$csrnum;
  my $count=0;
  eval {
    runSQL("declare csr_$csrnum cursor for $sql", @parms);
    for(;;) {
       $sth = $dbh->prepare("fetch 1000 from csr_$csrnum")
          or die "fetch 1000 from csr  $DBI::errstr\n";
       $sth->execute() or die "loopCursor fetch  $DBI::errstr\n";
       last if $sth->rows == 0;

       while ($row = $sth->fetchrow_hashref) {
        ++$count;
        &$proc($row);
       }
       $sth->finish();
    }
    runSQL("close csr_$csrnum");
    return $count;
  };
  die join(' ', "Error $@ during", $sql, @parms,
        $DBI::errstr||'',"\n") if $@;
}

sub runSQL
{
  my ($sql, @parms) = @_;
  my $sth;
  eval {
    $sth = $dbh->prepare($sql);
    $sth->execute(@parms) or die $DBI::errstr;
  };
  die "Error $@ during $sql @parms\n" if $@;
  $sth->finish();
  return $sth->rows;
}


---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux