Я хотел бы знать, как наиболее эффективно использовать память для извлечения произвольно больших полей данных из базы данных Oracle с помощью Perl DBI. Метод, который я знаю, чтобы использовать это установить атрибут LongReadLen на дескриптор базы данных на достаточно большой. Однако моему приложению нужно извлечь несколько тысяч записей, поэтому произвольное выполнение этого процесса крайне неэффективно.
doc предлагает выполнить запрос заранее, чтобы найти наибольшее потенциальное значение, и установить его.
$dbh->{LongReadLen} = $dbh->selectrow_array(qq{
SELECT MAX(OCTET_LENGTH(long_column_name))
FROM table WHERE ...
});
$sth = $dbh->prepare(qq{
SELECT long_column_name, ... FROM table WHERE ...
});
Однако это по-прежнему неэффективно, поскольку внешние данные не являются репрезентативными для каждой записи. Наибольшие значения превышают МБ, но средняя запись меньше, чем КБ. Я хочу иметь возможность извлекать всю информацию (т. Е. Без усечения), тратя при этом как можно меньше памяти на неиспользуемые буферы.
Метод, который я рассмотрел, состоит в том, чтобы извлекать данные порциями, скажем, по 50 записей за раз, и устанавливать LongReadLen относительно максимальной длины записей этого порции. Другой обходной путь, который может, но не обязан, основываться на идее чанка, заключался бы в том, чтобы разветвить дочерний процесс, извлечь данные, а затем убить дочерний процесс (забрав с собой потерянную память). Самой замечательной вещью была бы возможность принудительного освобождения буферов DBI, но я не думаю, что это возможно.
Кто-нибудь решал подобную проблему с каким-либо успехом? Спасибо за помощь!
EDIT
Perl v5.8.8, DBI v1.52
Чтобы уточнить: неэффективность памяти возникает из-за использования LongReadLen вместе с {ora_pers_lob => 1} в подготовке. Используя этот код:
my $sql = "select myclob from my table where id = 68683";
my $dbh = DBI->connect( "dbi:Oracle:$db", $user, $pass ) or croak $DBI::errstr;
print "before";
readline( *STDIN );
$dbh->{'LongReadLen'} = 2 * 1024 * 1024;
my $sth = $dbh->prepare( $sql, {'ora_pers_lob' => 1} ) or croak $dbh->errstr;
$sth->execute() or croak( 'Cant execute_query '. $dbh->errstr . ' sql: ' . $sql );
my $row = $sth->fetchrow_hashref;
print "after";
readline( *STDIN );
Использование резидентной памяти «до» составляет 18 МБ, а использование «после» - 30 МБ. Это недопустимо при большом количестве запросов.