2010-04-13 13 views
7
$s = explode (" ", microtime()); 
$s = $s[0]+$s[1]; 
$con = mysqli_connect ('localhost', 'test', 'pass', 'db') or die('Err'); 

for ($i=0; $i<1000; $i++) { 

    $stmt = $con -> prepare(" SELECT MAX(id) AS max_id , MIN(id) AS min_id FROM tb "); 
    $stmt -> execute(); 
    $stmt->bind_result($M,$m); 
    $stmt->free_result(); 
    $rand = mt_rand($m , $M).'<br/>'; 

    $res = $con -> prepare(" SELECT * FROM tb WHERE id >= ? LIMIT 0,1 "); 
    $res -> bind_param("s", $rand); 
    $res -> execute(); 
    $res->free_result(); 
} 

$e = explode (" ", microtime()); 
$e = $e[0]+$e[1]; 
echo number_format($e-$s, 4, '.', ''); 

// and: 

$link = mysql_connect ("localhost", "test", "pass") or die(); 
mysql_select_db ("db") or die ("Unable to select database".mysql_error()); 

for ($i=0; $i<1000; $i++) { 
    $range_result = mysql_query(" SELECT MAX(`id`) AS max_id , MIN(`id`) AS min_id FROM tb "); 
    $range_row = mysql_fetch_object($range_result); 
    $random = mt_rand($range_row->min_id , $range_row->max_id); 
    $result = mysql_query(" SELECT * FROM tb WHERE id >= $random LIMIT 0,1 "); 
} 

declaraciones defenitly preparados son mucho más seguras sino también en todas partes se dice que son mucho más rápidos pero en mi prueba en el código anterior tengo: - 2,45 seg para comandos preparados - 5.05 seg para la segunda ejemplo¿No deberían las declaraciones preparadas ser mucho más rápidas?

¿Qué crees que estoy haciendo mal? ¿Debo usar la segunda solución o debo tratar de optimizar la preparación?

+6

2.45 * es * más rápido que 5.05? –

+2

formatee el código para que sea legible. –

+0

OMG ... la gente no puede entender nada si escribe así ... formatéelo correctamente. –

Respuesta

23

Lo que está haciendo mal es que está preparando el enunciado mil veces y solo ejecuta cada enunciado preparado una vez. Debe prepararlo una vez y ejecutarlo mil veces.

+2

Para ser más claro, debe prepararlo una vez, y luego vincularlo y ejecutarlo mil veces. – MJB

+1

Eso es lo que sucede cuando las personas no comprenden el concepto de invariantes en bucles: -/ –

+0

Pongo ambas frases preparadas fuera del ciclo y ahora tengo aproximadamente 2.39 segundos y en sol.2 tenía 2.45. ¿Es normal? Es solo una mejora del 3%. – silversky

4

No es beneficioso preparar una instrucción dentro de un ciclo para una sola ejecución. Solo estás agregando sobrecarga. Use declaraciones preparadas para consultas que ejecute repetidamente, generalmente con diferentes parámetros.

+0

sí, fue un gran error poner stmt preparado dentro del ciclo, pero después de poner ambos prepararon el ciclo, el resultado es 2.39 segundos, que es solo 3% de aumento de velocidad ¿No debería ser más? – silversky

+1

no necesariamente. El principal ahorro es componer un plan de consulta para la consulta. Si se trata de una declaración SQL trivial, no hay mucho que guardar. Nada realmente se compila, por lo que realmente no hay ciclos de CPU de los que hablar, y si su consulta toca el disco (es decir, los datos no se almacenan en caché) eso amortiguará rápidamente cualquier ciclo de ahorro: los accesos al disco son mucho más lentos que los ciclos de CPU. – dkretz

+0

el db no es tan grande, solo tiene 42,000, pero esperaba mucho más ahorro. Pero probablemente tengas Wright. – silversky

1

Además de las respuestas anteriores ...

veo que está utilizando MySQL y por debajo es el enlace desde allí como a las declaraciones preparadas: http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html

Un extracto de allí:

El aumento en el rendimiento en las declaraciones preparadas puede provenir de algunas características diferentes. En primer lugar, es necesario analizar solo la consulta una sola vez. Cuando inicialmente prepara la declaración, MySQL analizará la declaración para verificar la sintaxis y configurar la consulta que se ejecutará. Luego, si ejecuta la consulta muchas veces, ya no tendrá esa sobrecarga. Esta pre-análisis puede conducir a un aumento de la velocidad si es necesario ejecutar la misma consulta muchas veces

+1

Como dije, sé que fue un gran error ponerlos dentro del ciclo, pero después de poner $ con -> preparar() afuera obtengo solo un incremento del 3-5% en la velocidad. se esperaba mucho más, al menos 20-30% de velocidad incrementado. – silversky

+0

¿Por qué esperaría un% de aumento de velocidad tan arbitrario? Las ganancias de rendimiento y sus medidas no funcionan de esa manera. Eso depende completamente del tamaño de los datos que está buscando y del rendimiento (vea mi respuesta para una mejor explicación). –

+0

Para agregar a eso, creo que debería esperar ganancias al usar declaraciones preparadas a largo plazo y el estado de su aplicación en forma de objetos menos temporales creados durante el análisis. No en números de ejecución sin procesar. Y como rara vez se sabe cuándo y cómo se usará una consulta (o cualquier fragmento de código) a lo largo del tiempo, es una buena práctica hacer que todas sean declaraciones preparadas. –

2

@silversy -

fundamentos Loop 101 (o llanura de codificación 101): código de lazo invariante movimiento de los bucles . ¿Por qué prepararías la declaración en el bucle cuando no toma parámetros que dependen del bucle en sí?

Por supuesto que va a chupar gónadas si utiliza comandos preparados si se les prepara con cada iteración del bucle. La sobrecarga que observa está en la declaración que se prepara inicialmente en lugar de en su ejecución.

Haga de nuevo el código de la siguiente manera, y volver a intentarlo de nuevo:

$stmt = $con -> prepare(" SELECT MAX(id) AS max_id , MIN(id) AS min_id FROM tb "); 
$res = $con -> prepare(" SELECT * FROM tb WHERE id >= ? LIMIT 0,1 "); 

for ($i=0; $i<1000; $i++) { 

    $stmt -> execute(); 
    $stmt->bind_result($M,$m); 
    $stmt->free_result(); 
    $rand = mt_rand($m , $M).'<br/>'; 

    $res -> bind_param("s", $rand); 
    $res -> execute(); 
    $res->free_result(); 
} 


La advertencia aquí, sin embargo, es que la diferencia entre una declaración preparada y uno no preparados se hace despreciable como el tiempo de cálculo para ejecutar la consulta y recuperar los datos se hace grande.

Sólo para tirar algunos números ficticios de mi @@@ por el bien de la ilustración:

decir que la consulta en sí y el ir a buscar los datos de la toma 0.01sec (llamamos a esto). Además, se imagina que la construcción y la ejecución del código detrás de una declaración preparada toma 0.01sec (X) y para la 0.05seg consulta sin preparación o 5 * 0,01 seg (Y = 5 * X).La ración entre el código preparado y sin preparación sería:

(A + Y)/(A + X) = 0.06sec/0.02sec = 3 -> unprepared execution is three times slower 

Y vamos a suponer que por otra consulta, el tiempo de ir a buscar (debido al volumen de datos o rendimiento de la red) es 10seg (1000 * 0.01sec). Entonces la relación cambia

(A + Y)/(A + X) = 10.05sec/10.01sec ~=~ 1.004 

Son casi indistinguibles. Lo que estoy tratando de decir es que sí, las declaraciones preparadas son más rápidas (y que debe usarlas), PERO la prueba que está implementando no es necesariamente una buena forma de averiguarlo o de evaluar su valor. Debes tener en cuenta otros factores para medir realmente el rendimiento que estás exprimiendo.

+0

@ uis.espinal, muchas gracias – silversky

Cuestiones relacionadas