PHP incluye la función para MySQL mysql_num_rows, que en base a un recurso procedente de una consulta MySQL, retorna un numérico que representa el total de registros que se han devuelto.
El sentido común indica que utilizar la consulta SQL usando COUNT(*) será probablemente algo más eficiente, basicamente por aquello de que todo lo relacionado con el manejo de los datos, lo gestiona mejor el propio SGBD.
Lo que yo no sabía, era que la diferencia fuera tan grande… Así, para una tabla con aproximadamente 50.000 artículos, el código con mysql_num_rows siguiente, ha requerido 0,175506 segundos, o un poco más de 5 consultas por segundo:
//Contar usando num_rows
$fInicio=microtime(true);
$sSQL="SELECT * FROM articulo ";
$rstListado=mysql_query($sSQL);
$iRows=mysql_num_rows($rstListado);
mysql_free_result($rstListado);
$fFinal=microtime(true);
echo "Contar num_rows: " . $iRows . "; Tiempo: " . ($fFinal-$fInicio) . "<br>";
Sobre los mismos datos, el equivalente usando la función COUNT, ha necesitado solamente 0,000182, lo que equivale a algo más de 5.000 consultas por segundo, es decir, casi 1000 veces más veloz que usando mysql_numrows:
//Contar usando COUNT
$fInicio=microtime(true);
$sSQL="SELECT COUNT(*) FROM articulo ";
$rstListado=mysql_query($sSQL);
$asListado=mysql_fetch_array($rstListado);
$iRows=$asListado[0];
mysql_free_result($rstListado);
$fFinal=microtime(true);
echo "Contar usando COUNT: " . $iRows . "; Tiempo: " . ($fFinal-$fInicio) . "<br>";
Muy bien, y ahora, ¿qué ocurriría si además de contarlos, necesitáramos obtenerlos? Aquí hay más dudas, pero la lógica dice que probablemente mysql_num_rows será más veloz, pues ejecutando una sola vez el SQL, obtenemos los datos y los contamos. Sería más o menos así:
//Contar y obtener con COUNT
$fInicio=microtime(true);
$sSQL="SELECT COUNT(*) FROM articulo ";
$rstListado=mysql_query($sSQL);
$asListado=mysql_fetch_array($rstListado);
$iRows=$asListado[0];
mysql_free_result($rstListado);
$sSQL="SELECT * FROM articulo ";
$rstListado=mysql_query($sSQL);
mysql_free_result($rstListado);
$fFinal=microtime(true);
echo "Contar y obtener con COUNT: " . $iRows . "; Tiempo: " . ($fFinal-$fInicio) . "<br>";
Sorprendentemente, a pesar de realizarse dos consultas, una de conteo y otra de obtención, el tiempo requerido ha sido de 0,169486 , que vienen a ser casi 6 consultas por segundo, es decir, más rápido que mysql_num_rows.
Sin duda, algo falla en la implementación de mysql_num_rows en PHP, que lo hace poco eficiente, por tanto ya sabéis, si solamente es para contar, mucho mejor COUNT. Si tenéis que contar y obtener, probablente, sea mejor también COUNT, aunque las pequeñas diferencias, pueden hacerlo variar en vuestros respectivos entornos.
Me parecio interesante la prueba que haces, incluso lo he proba y realmente count es mucho mas rapido por una gran ventaja que los otros metodos para consultar el numero de registros retornados.. pero realmente importan esos pocas centesimas de segundos ??.. y es que hago la pregunta porque me dio igual curiosidad de conocer los tiempo y tomando tu codigo hice mis pruebas con alrededor de 20,000 registros consultados 50 veces.. y luego obtuve un promedio de esos numeros.. y el resultado entre mysql_num_rows, count() + otra consulta para obtener los datos y otra forma en la que consultas directamente en la BD los registros retornados (SELECT FOUND_ROWS()).. los numeros que salieron fueron:
mysql_num_rows: 0.1389580488205
found_rows: 0.13642031669617
count: 0.00026428699493408
count+data: 0.13832779407501
Crees que realmente valga la pena dejar de utilizar mysql_num_rows por unas cuantas centesimas de segundos ???
Date cuenta Jack, que en tu caso, con mysql_num_rows, necesita 0,1389580488205 segundos, equivalente a 7 consultas por segundo, esto quiere decir, que solamente con 7 usuarios concurrentes en ese momento, se satura la máquina durante un segundo.
Como contrapartida, COUNT, te ha tardado apenas 0,00026428699493408 segundos, que son casi 4000 peticiones por segundo, sólo con este cambio, estás haciendo que tu aplicación escale un 57000%, sin tocar hardware.
Probablemente con pocos usuarios, el cambio sea despreciable, pero a medida que vaya aumentando la carga, y sobretodo la cantidad de registros a contar, este "pequeño detalle", marcará la aplicación entre una aplicación que ágil, y una que no.
Estoy totalmente de acuerdo con que COUNT es mucho mas rapido para obtener el numero de registros regresados, pero diferencias entre el uso de mysql_num_rows que me permite conocer el numero de filas retornadas aparte de poder obtener los datos de la consulta.. es una diferencia minima como para pensar dejar una funcion por la otra que conlleva mas codigo y mas validaciones. Entonces una consulta de conteo y otra de obtencion de datos hacen el mismo tiempo que un mysql_num_rows.
Ahora si se que mi aplicacion esta propensa a crecer quizas se pueda mejorar el rendimiento, cambiando el motor de las tablas incluso poniendo filtros que pueden mejorar el tiempo de respuesta de la consulta.
Perdon por la necedad, pero sigo pensando que hacer 2 consultas no es optimo, aunque me gusto tu post.. es polemico..
Saludos..
Hola Javier, Estás usando de forma incorrecta mysql_num_rows(). Esta función regresa el número de filas en un resultado (después de hacer un SELECT por ejemplo). Esta función "no cuenta", solo devuelve un valor del resulset generado después del SELECT.
En tu primer ejemplo, es obvio que te lleve más tiempo, ya que lo que te está consumiendo tiempo es la ejecución de la consulta SELECT y no la función mysql_num_rows(). Verificalo cambiando la línea $fInicio=microtime(true); después del mysql_query() 😉
Siempre que quieras contar fila no lo hagas con un SELECT y después un mysql_num_rows() porque, si bien arroja el mismo resultado, esto es ineficiente. La sentencia SQL COUNT está diseñada para eso, para contar. Por eso es mucho más rápido que un SELECT, porque un SELECT * recupera todos los datos de la tabla y te los trae a tu script (consumiendo más tiempo y obviamente memoria).
Saludos,
Pablo
Jack, naturalemente los números demuestran que si se desea contar, y obtener, las diferencias entre dos consultas, y mysql_num_rows son pequeñas. Aunque me inclino a pensar que debido al Query cache de MySQL, dos consultas será a medida que crezca la cantidad de resultados, comparativamente más eficiente que mysql_num_rows.
Pablo, estás en lo cierto, mysql_num_rows obtiene el número de filas, y devuelve los datos. El objeto del artículo era primeramente recomendar usar COUNT en sustitución a éste, cuando sólo se desean contar, y poner sobre la mesa que incluso una consulta de conteo y luego otra de obtención, puede resultar también más eficiente que mysq_num_rows.