2011-12-22 74 views
6

我有一些看起来像这样:加快perl的DBI fetchrow_hashref

my $report = new ReportGenerator; #custom object 
my $dbh = $dbc->prepare('SELECT * FROM some_table WHERE some_condition'); #DBI handle 
$dbh->execute(); 
while(my $href = $dbh->fetchrow_hashref){ 
    $report->process_record($href); 
} 
$dbh->finish(); 
print $report->printReport(); 

我的问题是,每次循环很慢。问题是MySQL。我想知道是否有可能在while循环中放置某种包装以使其一次获取多条记录,同时将所有记录提取到内存中也是不现实的。我并不担心代码的效率(hashref vs arrayref等)。相反,我有兴趣提取一次允许说10000条记录。

该数据库有约500万条记录。我无法更改/升级服务器。

感谢

+0

该代码应该足够快地运行。你确定选择不需要很长时间运行?您可能需要时间执行需要多长时间。当然,你的过程可能会很慢。您可能会尝试在没有进程的情况下计时。 – 2011-12-22 16:32:26

回答

8

您可以使用它接受一个“MAXROWS”参数的fetchall_arrayref功能:

while (my $data = $dbc->fetchall_arrayref(undef, 10000)) { 
    for my $row(@{$data}) { 
    $report->process_record($row); 
    } 
} 

你也可以看看它试图控制多少条记录在获取返回的RowCacheSize财产从你的司机。

+1

当您仅仅处理一个记录并丢弃它们时,不建议使用fetchall_arrayref。这是因为它需要大量内存分配来存储所有行的所有字段,并且内存分配很昂贵。请参阅http://www.slideshare.net/Tim.Bunce/dbi-advanced-tutorial-2007的第22页 – 2011-12-29 23:30:51

4

哪位慢?是否拨打execute,fetchrow_hashrefprocess_record?对我而言,fetchrow_hashref不太可能是问题。执行查询或process_record的黑盒子的可能性更大。

但这一切猜测。在这里真的不可能帮到你。我建议你使用Devel::NYTProf来获得一些有关代码性能的真实数据。

+0

我已经这样做了,发现问题与此问题无关,即表示这两种方法都非常接近彼此。 221秒vs 239秒。所以仍然有一点改善。尽管我发现了一个有趣的哈希查找瓶颈。我有一个函数,检查哈希是否存在,如果它获得了一个值,如果它是剂量,它会从MySQL中取出它。平均平均4μs/通话。问题是这个函数被调用了1500万次。这几乎是1分钟。但那不是一件容易修复的事情。 – Smartelf 2011-12-22 18:17:12

3

读取行与使用DBI哈希最快的方法是使用bind_columns()这样的:

$sth->execute; 
    my %row; 
    $sth->bind_columns(\(@row{ @{$sth->{NAME_lc} } })); 
    while ($sth->fetch) { 
     print "$row{region}: $row{sales}\n"; 
    } 

如果你感到快乐的每一行重复使用相同的散列这只是适当的。

除此之外,我同意davorg,避免猜测:首先测量。

有关使用DBI的更多信息,包括性能,请参阅我的tutorial slides(从2007年开始,但仍然相关)。