Re: out of memory for query result

Поиск
Список
Период
Сортировка
От Allen
Тема Re: out of memory for query result
Дата
Msg-id 435C24DB.3060207@girders.org
обсуждение исходный текст
Ответ на Re: out of memory for query result  (Martijn van Oosterhout <kleptog@svana.org>)
Список pgsql-general
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;
}


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

Предыдущее
От: Steve V
Дата:
Сообщение: Re: Transaction IDs not the same in same transaction?
Следующее
От: Neil Conway
Дата:
Сообщение: Re: Transaction IDs not the same in same transaction?