2011-12-22 75 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年開始,但仍然相關)。