加速perl DBI fetchrow_hashref

时间:2011-12-22 14:32:40

标签: mysql sql database performance perl

我有一些看起来像这样的东西:

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万条记录。我无法更改/升级服务器。

由于

3 个答案:

答案 0 :(得分:8)

您可以使用接受'maxrows'参数的fetchall_arrayref函数:

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

您还可以查看RowCacheSize属性,该属性尝试控制从驱动程序中获取的返回记录数。

答案 1 :(得分:4)

哪一点很慢?是executefetchrow_hashref还是process_record的来电? fetchrow_hashref问题似乎不太可能。它更有可能是执行查询或process_record的黑匣子。

但这一切都在猜测。这里真的不可能有所帮助。我建议您使用Devel::NYTProf获取有关代码性能的实际数据。

答案 2 :(得分: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年开始,但仍然相关)。