我想知道用Perl DBI从Oracle数据库中随机抽取大数据字段的最有效的方法。 我知道要使用的方法是将数据库句柄上的“LongReadLen”属性设置为足够大。 但是,我的应用程序需要提取数千条logging,因此这样做是非常有效的。
文件build议先做一个查询,find最大的潜在价值,并设置。
$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 ... });
然而,这仍然是低效的,因为偏离的数据并不代表每个logging。 最大值超过一个MB,但平均logging小于KB。 我希望能够在尽可能less地浪费未使用的缓冲区的同时浪费所有的信息(即不截断)。
我已经考虑过的一种方法是将数据分块(比如说50个logging),并将LongReadLen设置为该块的最大logging长度。 另一个解决方法,可以但不一定要build立在大块的想法基础上,将分叉subprocess,检索数据,然后杀死孩子(带着浪费的内存)。 最好的事情就是强制释放DBI缓冲区的能力,但我认为这是不可能的。
有没有人解决了类似的问题,取得了成功? 谢谢您的帮助!
编辑
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 );
居民内存使用“之前”是在18MB和使用“之后”在30MB。 这在大量的查询中是不可接受的。
您的列是否有大数据LOB(CLOB或BLOB)? 如果是这样,你根本不需要使用LongReadLen; DBD :: Oracle提供了一个LOB流式接口。
你想要做的就是将参数绑定为类型ORA_CLOB
或ORA_BLOB
,这将得到你从查询返回的“LOB定位器”,而不是tex。 然后你使用ora_lob_read和LOB定位器来获取数据。 下面是一个适用于我的代码示例:
sub read_lob { my ( $dbh, $clob ) = @_; my $BLOCK_SIZE = 16384; my $out; my $offset = 1; while ( my $data = $dbh->ora_lob_read( $clob, $offset, $BLOCK_SIZE ) ) { $out .= $data; $offset += $BLOCK_SIZE; } return $out; }
我这样想:
use Parallel::ForkManager use strict; # Max 50 processes for parallel data retrieving my $pm = new Parallel::ForkManager(50); # while loop goes here while (my @row = $sth->fetchrow_array) { # do the fork $pm->start and next; # # Data retreiving goes here # # do the exit in the child process $pm->finish; } $pm->wait_all_children;
检查CPAN中的 Parallel :: ForkManager以了解更多信息。