2011-12-22 19 views
6

tengo algo que se parece a esto:Acelerar 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(); 

Mi problema es que cada iteración del bucle es muy lento. El problema es el MySQL. Me preguntaba si era posible colocar algún tipo de envoltorio en el ciclo while para hacer que captara más de un registro a la vez, al mismo tiempo, tampoco es práctico recuperar todos los registros en la memoria. No me preocupa la eficacia del código (hashref vs arrayref, etc.). Más bien, estoy interesado en ir a buscar, digamos 10000 registros a la vez.

La base de datos tiene ~ 5 Millones de registros. No puedo cambiar/actualizar el servidor.

Gracias

+0

Ese código debería ejecutarse lo suficientemente rápido. ¿Estás seguro de que la selección no tarda mucho tiempo en ejecutarse? Es posible que desee cronometrar cuánto tiempo tarda la ejecución. Y, por supuesto, su proceso podría ser lento. Puede intentar cronometrar solo la búsqueda sin el proceso. –

Respuesta

8

Puede utilizar la función fetchall_arrayref que acepta un argumento 'maxRows':

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

También podría mirar a la propiedad RowCacheSize que intenta controlar el número de registros se devuelven en una zona de alcance de tu conductor.

+1

fetchall_arrayref no se recomienda cuando simplemente procesa registros de uno en uno y los descarta. Esto se debe a que tiene que hacer muchas asignaciones de memoria para almacenar todos los campos de todas las filas, y las asignaciones de memoria son costosas. Ver página 22 de http://www.slideshare.net/Tim.Bunce/dbi-advanced-tutorial-2007 –

4

¿Qué bit es lento? ¿Es la llamada al execute, fetchrow_hashref o process_record? Me parece poco probable que fetchrow_hashref sea el problema. Es mucho más probable que sea la ejecución de la consulta o la caja negra de process_record.

Pero esto es toda una conjetura. Es imposible realmente ayudar aquí. Te recomiendo que obtengas datos reales sobre el rendimiento del código usando Devel::NYTProf.

+0

Ya estaba haciendo eso y encontré que el problema no está relacionado con esta pregunta, que ambos métodos son bastante parecidos a El uno al otro. 221seg frente a 239 seg. Entonces, todavía hay una ligera mejoría. aunque encontré un cuello de botella interesante en una búsqueda hash. Tengo una función que comprueba si existe el hash, si lo hace obtiene un valor, y si es dosent, lo extrae de mysql. con un promedio de avg 4μs/llamada. el problema es que la función se llama 15 millones de veces. que es casi 1 minuto. pero eso no es algo que se pueda arreglar fácilmente. – Smartelf

3

La forma más rápida para recuperar filas como hash utilizando el DBI es utilizar bind_columns() así:

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

Eso es muy apropiada si eres feliz para cada fila de reutilizar el mismo hash.

Más allá de eso, estoy de acuerdo con davorg, evite las conjeturas: mida primero.

Para obtener más información sobre el uso de DBI, incluido el rendimiento, consulte mi tutorial slides (desde 2007, pero sigue siendo relevante).

Cuestiones relacionadas