selección rápida de una fila aleatoria de una tabla grande en mysql

Resuelto lajos asked hace 16 años • 24 respuestas

¿Cuál es una forma rápida de seleccionar una fila aleatoria de una tabla MySQL grande?

Estoy trabajando en php, pero me interesa alguna solución aunque sea en otro idioma.

lajos avatar Oct 17 '08 14:10 lajos
Aceptado

Tome todas las identificaciones, elija una al azar y recupere la fila completa.

Si sabe que las identificaciones son secuenciales sin agujeros, puede simplemente tomar el máximo y calcular una identificación aleatoria.

Si hay agujeros aquí y allá, pero en su mayoría valores secuenciales, y no le importa una aleatoriedad ligeramente sesgada, tome el valor máximo, calcule una identificación y seleccione la primera fila con una identificación igual o superior a la que calculó. La razón del sesgo es que las identificaciones que siguen tales agujeros tendrán una mayor probabilidad de ser elegidas que las que siguen a otra identificación.

Si realiza un pedido al azar, tendrá un terrible escaneo de mesa en sus manos, y la palabra rápido no se aplica a tal solución.

No hagas eso, ni ordenes por GUID, tiene el mismo problema.

Lasse V. Karlsen avatar Oct 17 '2008 07:10 Lasse V. Karlsen

Sabía que tenía que haber una manera de hacerlo en una sola consulta de forma rápida. Y aquí está:

Una forma rápida sin la participación de código externo, felicitaciones a

http://jan.kneschke.de/projects/mysql/order-by-rand/

SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1;
Vinko Vrsalovic avatar Oct 17 '2008 08:10 Vinko Vrsalovic

MediaWiki utiliza un truco interesante (para la función Especial:Aleatorio de Wikipedia): la tabla con los artículos tiene una columna adicional con un número aleatorio (generado cuando se crea el artículo). Para obtener un artículo aleatorio, genere un número aleatorio y obtenga el artículo con el siguiente valor mayor o menor (no recuerdo cuál) en la columna de números aleatorios. Con un índice, esto puede ser muy rápido. (Y MediaWiki está escrito en PHP y desarrollado para MySQL).

Este enfoque puede causar un problema si los números resultantes están mal distribuidos; IIRC, esto se ha solucionado en MediaWiki, por lo que si decide hacerlo de esta manera, debe echar un vistazo al código para ver cómo se hace actualmente (probablemente regeneran periódicamente la columna de números aleatorios).

CesarB avatar Oct 18 '2008 04:10 CesarB

Aquí hay una solución que se ejecuta con bastante rapidez y obtiene una mejor distribución aleatoria sin depender de que los valores de identificación sean contiguos o comiencen en 1.

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
Bill Karwin avatar Oct 17 '2008 18:10 Bill Karwin

Quizás podrías hacer algo como:

SELECT * FROM table 
  WHERE id=
    (FLOOR(RAND() * 
           (SELECT COUNT(*) FROM table)
          )
    );

Esto supone que sus números de identificación son todos secuenciales y sin espacios.

davr avatar Sep 26 '2008 22:09 davr