Si realizamos una búsqueda en google sobre como realizar una consulta que genere resultados aleatorios, una de las primeras cosas que nos encontramos es que usar en la consulta RAND() o su versión mas eficiente MT_RAND() es poco eficiente y genera un gran consumo de recursos de servidor. Se dice que el uso de MT_RAND() con una consulta LIMIT genera un gran consumo de recursos, pero si lo hacemos con bucles, tal consumo se reduce. Mis comprobaciones más bien han dado un resultado contrario. Además, no encuentro lógica en las afirmaciones en este sentido, sobre todo, por que en ambos métodos es necesario usar MT_RAND(), y en el caso de usar LIMIT, no veo sentido en que el uso de LIMIT, genere tanto consumo de recursos.
Dicho esto, entramos en materia. He desarrollado dos métodos de aleatorización de resultados. El método A usa MT_RAND() y LIMIT, el segundo, método B usa arrays y bucles, donde también es preciso que usemos MT_RAND().
Veamos el método A.
La lógica del método A radica en el uso de LIMIT como forma de determinar desde que resultado mostramos registros, y cuantos registros mostramos. Recordemos la forma de una consulta LIMIT:
LIMIT registro inicial, cuantos registros
Podemos también determinar si lo hacemos en sentido ascendente o descendente mediante ORDER BY campo ASC/DESC. En este sentido, tenemos que tener mucho cuidado con que valor asignamos como inicio del LIMIT. Explico este punto.
Imaginemos que tenemos una tabla con 100 registros, y queremos extraer 10 de manera aleatoria. Cualquiera pensaría en generar un aleatorio entre 1 y 100, pero esto daría menos de 10 registros en algunos casos. Esto ocurriría si el aleatorio fuera 97, por ejemplo, y hemos elegido orden ascendente. En este caso, por encima de 97 solo hay tres registros. Y si el orden es descendente, si el aleatorio fuera 3, por debajo de ese valor, solo tendríamos 2 registros. Por estos motivos, debemos restar del total de registros el número de registros que queremos extraer si nos decantamos por un orden ascendente, o iniciar el LIMIT en el número de registros que queremos extraer si usamos el orden descendente.
Este método de aleatorización tiene un problema, y es que como solo se determina de manera aleatoria el comienzo del LIMIT, los demás registros siempre serán los adyacentes a este, por encima o por debajo según el orden que asignemos.
Dicho esto, el resto del código no tiene ninguna novedad respecto a una lectura de tabla ordinaria. Presentamos este código como “Método A”.
Veamos ahora el método B.
Este metido sigue una lógica diferente y no radica en el tipo de consulta SQL como en el caso anterior. Ahora lo que hacemos es generar un array con los registros de la tabla. Generamos mediante un buble un grupo de valores aleatorios, tantos como resultados queremos obtener, y se corresponden con el rango de valores de las claves del array. Con esto, teniendo las claves, ya podemos obtener los valores del array, y estos son nuestros resultados aleatorios.
Este método tiene una ventaja sobre el anterior, y es que los resultados son realmente aleatorios (mas bien seudoaleatorios, ya que MT_RAND() genera valores seudoaleatorios).
Este método, si bien tiene este ultima ventaja, consume mas recursos de servidor que el metido A, considerado el “peor” en la mayoría de los sitios Web consultados. Y consume mas recursos que el anterior, por que si bien en el método A solo hay un solo bucle while, en el método B hay tres bucles, uno while, uno for y otro foreach. Presentamos este código como “Método B”.
Para comprobar esto, he agregado una medición de recursos de memoria consumida al inicio y al final de cada código. Que cada cual saque sus conclusiones y elija la opción que mas convenga a sus necesidades.
============= METODO A: Registros aleatorios con LIMIT.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="iso-8859-1" />
<title>Registros aleatorios de una consulta MySQL usando RAND y LIMIT.</title>
<meta name="robots" content="noindex, nofollow" />
</head>
<body>
<H3 align="center">METODO A: Registros aleatorios con LIMIT.</H3>
<div align="center">
<table border="1" width="700" id="table1">
<?php
error_reporting(-1);
ini_set("display_errors", 1);
// MEDIMOS LA MEMORIA CONSUMIDA EN LA EJECUCION DEL CODIGO ANTES
// DE INICIAR LA CONEXION A LA BASE DE DATOS
// Muestra la memoria usada antes de ejecutar el codigo
$memoria_antes = memory_get_usage();
$memoria_antes_kb = round($memoria_antes / 1024, 2);
// echo "$memoria_antes_kb Kb <br />";
// FIN DE LA MEDICION DE MEMORIA CONSUMIDA ANTES DE EJECUTAR EL CODIGO
include("../abre_conexion.php");
// Generamos una consulta que muestra resultados aleatorios
// ------ Contamos numero de registros
$_Cuen_1 = " SELECT * FROM $tabla_db1 ";
$_Cuenta_1 = mysql_query($_Cuen_1);
$_Total_1 = mysql_num_rows($_Cuenta_1);
$total_resgistros = $_Total_1; // Total registros en la tabla
$n_registros = 10; // <<<<<<<<< Numero de registros a generar MODIFICAR
$aleatorio = mt_rand(1, $total_resgistros - $n_registros);
$_pagi_sql = " SELECT id, nombre, email, fecha, hora FROM $tabla_db1 ORDER BY id ASC LIMIT $aleatorio, $n_registros ";
$_pagi_result = mysql_query($_pagi_sql);
while ($registro = mysql_fetch_array($_pagi_result)){
echo "
<tr>
<td class=\"celda1\">".$registro['id']."</td>
<td class=\"celda1\">".$registro['nombre']."</td>
<td class=\"celda1\">".$registro['email']."</td>
<td class=\"celda1\">".$registro['fecha']."</td>
<td class=\"celda1\">".$registro['hora']."</td>
</tr>
";
}
include("../cierra_conexion.php");
// MEDIMOS LA MEMORIA CONSUMIDA EN LA EJECUCION DEL CODIGO DESPUES
// DE INICIAR LA CONEXION A LA BASE DE DATOS
// Muestra la memoria usada despues de ejecutar el codigo
$memoria_despues = memory_get_usage();
$memoria_despues_kb = round($memoria_despues / 1024, 2);
// echo "$memoria_despues_kb Kb <br />";
$memoria_usada = $memoria_despues - $memoria_antes;
$_memoria_antes = round($memoria_antes / 1024, 2);
$_memoria_despues = round($memoria_despues / 1024, 2);
$_memoria_usada = round($memoria_usada / 1024, 2);
$porcentaje = round(($memoria_usada * 100) / $memoria_antes, 2);
// FIN DE LA MEDICION DE MEMORIA CONSUMIDA DESPUES DE EJECUTAR EL CODIGO
echo "
</table>
</div>
<p>
Memoria consumida antes de la ejecucion de la consulta: $_memoria_antes Kb <br />
Memoria consumida despues de la ejecucion de la consulta: $_memoria_despues Kb <br />
Memoria consumida por la ejecucion de la consulta: $_memoria_usada Kb <br />
Incremento de memoria consumida: $porcentaje%
</p>";
?>
<p align="center"><a target="_blank" href="../id103/lista2.php">Tabla de donde extraemos los resgistros aleatorios</a></p>
<p align="center"><a href="reg_aleatorios.php">Generador de aleatorios con bucles en MySQL</a></p>
</body>
</html>
================================================================================
============= METODO B: Registros aleatorios con BUCLES.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="iso-8859-1" />
<title>Registros aleatorios de una consulta MySQL usando bucles.</title>
<meta name="robots" content="noindex, nofollow" />
</head>
<body>
<H3 align="center">METODO B: Registros aleatorios con BUCLES.</H3>
<div align="center">
<table border="1" width="700" id="table1">
<?php
error_reporting(-1);
ini_set("display_errors", 1);
// MEDIMOS LA MEMORIA CONSUMIDA EN LA EJECUCION DEL CODIGO ANTES
// DE INICIAR LA CONEXION A LA BASE DE DATOS
// Muestra la memoria usada antes de ejecutar el codigo
$memoria_antes = memory_get_usage();
$memoria_antes_kb = round($memoria_antes / 1024, 2);
// echo "$memoria_antes_kb Kb <br />";
// FIN DE LA MEDICION DE MEMORIA CONSUMIDA ANTES DE EJECUTAR EL CODIGO
include("../abre_conexion.php");
// Generamos una consulta que muestra resultados aleatorios
$_pagi_sql = " SELECT id, nombre, email, fecha, hora FROM $tabla_db1 ";
$_pagi_result = mysql_query($_pagi_sql);
$_total_registros = mysql_num_rows($_pagi_result);
$array_multi_registro = array(); // Creamos array
$i = 0;
while($registro = mysql_fetch_array($_pagi_result)) {
$array_multi_registro[$i] = $registro;
$i++;
$n_elemen_array = count($array_multi_registro);
}
$Num_Regis = 10; // <<<<<<<<< Numero de registros a generar MODIFICAR
$_Val_min = 0; // Valor minimo
$_Val_max = $n_elemen_array - 1; // Valor maximo
if($Num_Regis > $_Val_max) {
echo "<p>No es posible generar $Num_Regis registros aleatorios por la que tabla contine $_Val_max registros.</p>";
} else {
$_nuM = Array();
reset($_nuM);
for($i=1; $i<=$Num_Regis; $i++) {
$_nuM[$i]=MT_RAND($_Val_min, $_Val_max); if($i>1) {
for($x=1; $x<$i; $x++) { if($_nuM[$i]==$_nuM[$x]) { $i--;
break; } } } }
foreach($_nuM as $array_reg) {
@$reg_id = $array_multi_registro[$array_reg][id];
@$reg_nombre = $array_multi_registro[$array_reg][nombre];
@$reg_email = $array_multi_registro[$array_reg][email];
@$reg_fecha = $array_multi_registro[$array_reg][fecha];
@$reg_hora = $array_multi_registro[$array_reg][hora];
echo "
<tr>
<td class=\"celda1\">$reg_id</td>
<td class=\"celda1\">$reg_nombre</td>
<td class=\"celda1\">$reg_email</td>
<td class=\"celda1\">$reg_fecha</td>
<td class=\"celda1\">$reg_hora</td>
</tr>
";
}
}
include("../cierra_conexion.php");
// MEDIMOS LA MEMORIA CONSUMIDA EN LA EJECUCION DEL CODIGO DESPUES
// DE INICIAR LA CONEXION A LA BASE DE DATOS
// Muestra la memoria usada despues de ejecutar el codigo
$memoria_despues = memory_get_usage();
$memoria_despues_kb = round($memoria_despues / 1024, 2);
// echo "$memoria_despues_kb Kb <br />";
$memoria_usada = $memoria_despues - $memoria_antes;
$_memoria_antes = round($memoria_antes / 1024, 2);
$_memoria_despues = round($memoria_despues / 1024, 2);
$_memoria_usada = round($memoria_usada / 1024, 2);
$porcentaje = round(($memoria_usada * 100) / $memoria_antes, 2);
// FIN DE LA MEDICION DE MEMORIA CONSUMIDA DESPUES DE EJECUTAR EL CODIGO
echo "
</table>
</div>
<p>
Memoria consumida antes de la ejecucion de la consulta: $_memoria_antes Kb <br />
Memoria consumida despues de la ejecucion de la consulta: $_memoria_despues Kb <br />
Memoria consumida por la ejecucion de la consulta: $_memoria_usada Kb <br />
Incremento de memoria consumida: $porcentaje%
</p>";
?>
<p align="center"><a target="_blank" href="../id103/lista2.php">Tabla de donde extraemos los resgistros aleatorios</a></p>
<p align="center"><a href="reg_aleatorios_limit.php">Generador de aleatorios con LIMIT en MySQL</a></p>
</body>
</html>