2011-12-22 17 views
6

tôi có cái gì đó trông như thế này:Đẩy nhanh 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(); 

Vấn đề của tôi là mỗi lần lặp của vòng lặp là rất chậm. Vấn đề là MySQL. Tôi đã tự hỏi nếu nó có thể đặt một số loại wrapper trong vòng lặp while để làm cho nó lấy nhiều hơn một bản ghi tại một thời điểm, cùng một lúc, lấy tất cả các bản ghi vào bộ nhớ là không thực tế hoặc. Tôi không lo lắng về hiệu quả của mã (hashref vs arrayref, vv ..). Thay vào đó, tôi quan tâm đến việc tìm nạp cho phép nói 10000 bản ghi tại một thời điểm.

Cơ sở dữ liệu có ~ 5 triệu bản ghi. Tôi không thể thay đổi/nâng cấp máy chủ.

Cảm ơn

+0

Mã đó phải chạy đủ nhanh. Bạn có chắc chắn rằng việc chọn không mất nhiều thời gian để chạy? Bạn có thể muốn thời gian thực hiện. Và tất nhiên, quá trình của bạn có thể chậm. Bạn có thể thử chỉ định thời gian tìm nạp mà không cần xử lý. –

Trả lời

8

Bạn có thể sử dụng chức năng fetchall_arrayref mà chấp nhận một cuộc tranh luận 'maxrows':

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

Bạn cũng có thể nhìn vào RowCacheSize tài sản mà cố gắng để kiểm soát có bao nhiêu hồ sơ được trả về trong một lấy từ tài xế của bạn.

+1

fetchall_arrayref không được khuyến nghị khi bạn chỉ xử lý một bản ghi một lần và loại bỏ chúng. Đó là bởi vì nó phải tạo ra rất nhiều phân bổ bộ nhớ để lưu trữ tất cả các trường của tất cả các hàng và phân bổ bộ nhớ rất tốn kém. Xem trang 22 của http://www.slideshare.net/Tim.Bunce/dbi-advanced-tutorial-2007 –

4

Tốc độ bit chậm? Đây có phải là cuộc gọi tới execute, fetchrow_hashref hoặc process_record? Dường như tôi không chắc rằng fetchrow_hashref là vấn đề. Nó có nhiều khả năng là việc thực hiện truy vấn hoặc hộp đen của process_record.

Nhưng tất cả những phỏng đoán này. Nó không thể thực sự giúp đỡ ở đây. Tôi khuyên bạn nên lấy một số dữ liệu thực sự về hiệu suất của mã bằng cách sử dụng Devel::NYTProf.

+0

Tôi đã làm việc đó và thấy rằng vấn đề không liên quan đến câu hỏi này, cho biết cả hai phương pháp đều khá gần với lẫn nhau. 221 giây so với 239 giây. Vì vậy, vẫn còn có một chút cải thiện. mặc dù tôi đã tìm thấy một nút cổ chai thú vị trong một tra cứu băm. Tôi có một chức năng kiểm tra nếu băm tồn tại, nếu nó nhận được một giá trị, và nếu nó dosent, nó kéo nó từ mysql. với mức trung bình là 4µs/cuộc gọi. vấn đề là hàm được gọi là 15 triệu lần. đó là gần 1 phút. nhưng đó không phải là một cái gì đó có thể được cố định easiily. – Smartelf

3

Cách nhanh nhất để lấy hàng như băm bằng cách sử dụng DBI là sử dụng bind_columns() như thế này:

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

Đó là chỉ thích hợp nếu bạn đang hạnh phúc cho mỗi hàng để tái sử dụng cùng bảng băm.

Ngoài ra, tôi đồng ý với davorg, tránh phỏng đoán: đo trước tiên.

Để biết thêm thông tin về việc sử dụng DBI, bao gồm cả hiệu suất, hãy xem tutorial slides của tôi (từ năm 2007, nhưng vẫn có liên quan).

Các vấn đề liên quan