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

¿Cuál es una forma rápida de seleccionar una fila aleatoria de una gran tabla mysql?

Estoy trabajando en php, pero estoy interesado en cualquier solución, incluso si está en otro idioma.

Toma todas las identificaciones, elige una aleatoria y recupera la fila completa.

Si sabes que los identificadores son secuenciales sin agujeros, puedes tomar el máximo y calcular una identificación aleatoria.

Si hay agujeros aquí y allá pero en su mayoría son valores secuenciales, y no te importa una aleatoriedad ligeramente sesgada, toma el valor máximo, calcula una identificación y selecciona la primera fila con una identificación igual o superior a la que calculaste. La razón del sesgo es que los siguientes huecos de identificación tendrán una mayor probabilidad de ser recogidos que los que siguen a otra identificación.

Si ordena al azar, va a tener un terrible escaneo de mesa en sus manos, y la palabra rápida no se aplica a tal solución.

No hagas eso, ni deberías ordenar por un GUID, tiene el mismo problema.

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

Una manera 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; 

MediaWiki usa un truco interesante (para la característica Especial de Wikipedia: Aleatoriedad): 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 al azar, genere un número aleatorio y obtenga el artículo con el siguiente valor más grande o más pequeño (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 corregido en MediaWiki, por lo que si decides hacerlo de esta manera, deberías echarle un vistazo al código para ver cómo se hace actualmente (probablemente regeneren periódicamente la columna de números aleatorios).

Aquí hay una solución que se ejecuta con bastante rapidez y que obtiene una mejor distribución aleatoria sin depender de que los valores de ID 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; 

Tal vez 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 sin espacios vacíos.

Agregue una columna que contenga un valor aleatorio calculado para cada fila, y utilícela en la cláusula de ordenamiento, limitándose a un resultado luego de la selección. Esto funciona más rápido que tener el escaneo de tabla que causa ORDER BY RANDOM() .

Actualización: aún necesita calcular algún valor aleatorio antes de emitir la instrucción SELECT al recuperar, por supuesto, por ejemplo

 SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1 

Una manera fácil pero lenta sería (bueno para las tablas más bien pequeñas)

 SELECT * from TABLE order by RAND() LIMIT 1 

En pseudo código:

 sql "select id from table" store result in list n = random(size of list) sql "select * from table where id=" + list[n] 

Esto supone que id es una clave única (primaria).

Hay otra manera de producir filas aleatorias utilizando solo una consulta y sin orden por rand (). Implica variables definidas por el usuario. Vea cómo producir filas aleatorias de una tabla

Para encontrar filas aleatorias de una tabla, no use ORDER BY RAND () porque obliga a MySQL a realizar una ordenación completa de archivos y solo luego a recuperar el número de filas límite requerido. Para evitar este tipo de archivo completo, use la función RAND () solo en la cláusula where. Se detendrá tan pronto como llegue al número requerido de filas. Ver http://www.rndblog.com/how-to-select-random-rows-in-mysql/

Si no elimina la fila en esta tabla, la forma más eficiente es:

(si conoce la id. mínima simplemente saltéela)

 SELECT MIN(id) AS minId, MAX(id) AS maxId FROM table WHERE 1 $randId=mt_rand((int)$row['minId'], (int)$row['maxId']); SELECT id,name,... FROM table WHERE id=$randId LIMIT 1 

Para seleccionar múltiples filas aleatorias de una tabla determinada (digamos ‘palabras’), nuestro equipo ideó esta belleza:

 SELECT * FROM `words` AS r1 JOIN (SELECT MAX(`WordID`) as wid_c FROM `words`) as tmp1 WHERE r1.WordID >= (SELECT (RAND() * tmp1.wid_c) AS id) LIMIT n 

El clásico “SELECT ID FROM table ORDER BY RAND () LIMIT 1” está realmente bien.

Vea el siguiente fragmento del manual de MySQL:

Si usa LIMIT row_count con ORDER BY, MySQL finaliza la clasificación tan pronto como encuentra las primeras filas row_count del resultado ordenado, en lugar de ordenar el resultado completo.

Con un pedido, harás una tabla de exploración completa. Es mejor si haces un conteo selecto (*) y luego obtienes una fila aleatoria = rownum entre 0 y el último registro

Eche un vistazo a este enlace de Jan Kneschke o esta respuesta SO, ya que ambos discuten la misma pregunta. La respuesta SO revisa varias opciones también y tiene algunas buenas sugerencias dependiendo de sus necesidades. Jan repasa todas las diversas opciones y las características de rendimiento de cada una. Él termina con lo siguiente para el método más optimizado por el cual hacer esto dentro de una selección de MySQL:

 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; 

HTH,

-Dipin

Soy un poco nuevo en SQL, pero ¿qué hay de generar un número aleatorio en PHP y el uso

 SELECT * FROM the_table WHERE primary_key >= $randNr 

esto no resuelve el problema con los agujeros en la mesa.

Pero aquí hay un giro en la sugerencia de lassevks:

 SELECT primary_key FROM the_table 

Use mysql_num_rows () en PHP cree un número aleatorio basado en el resultado anterior:

 SELECT * FROM the_table WHERE primary_key = rand_number 

En una nota lateral, cuán lento es SELECT * FROM the_table :
Creando un número aleatorio basado en mysql_num_rows() y luego moviendo el puntero de datos a ese punto mysql_data_seek() . ¿Qué tan lento será esto en grandes mesas con un millón de filas?

Me encontré con el problema donde mis identificaciones no eran secuenciales. Lo que se me ocurrió con esto.

 SELECT * FROM products WHERE RAND()<=(5/(SELECT COUNT(*) FROM products)) LIMIT 1 

Las filas devueltas son aproximadamente 5, pero la limito a 1.

Si desea agregar otra cláusula WHERE, se vuelve un poco más interesante. Supongamos que quiere buscar productos con descuento.

 SELECT * FROM products WHERE RAND()<=(100/(SELECT COUNT(*) FROM pt_products)) AND discount<.2 LIMIT 1 

Lo que tiene que hacer es asegurarse de que está devolviendo el resultado suficiente, por eso lo tengo configurado en 100. Tener una cláusula de descuento WHERE <.2 en la subconsulta fue 10 veces más lento, por lo que es mejor devolver más resultados y límite.

Veo aquí mucha solución. Uno o dos parece estar bien, pero otras soluciones tienen algunas limitaciones. Pero la siguiente solución funcionará para todas las situaciones

 select a.* from random_data a, (select max(id)*rand() randid from random_data) b where a.id >= b.randid limit 1; 

Aquí, id, no es necesario que sea secuencial. Podría ser cualquier columna de clave principal / único / incremento automático. Consulte la siguiente forma más rápida para seleccionar una fila aleatoria de una gran tabla MySQL

Gracias Zillur – http://www.techinfobest.com

Use la consulta a continuación para obtener la fila aleatoria

 SELECT user_firstname , COUNT(DISTINCT usr_fk_id) cnt FROM userdetails GROUP BY usr_fk_id ORDER BY cnt ASC LIMIT 1 

En mi caso, mi tabla tiene una identificación como clave principal, autoincremento sin espacios vacíos, por lo que puedo usar COUNT(*) o MAX(id) para obtener el número de filas.

Hice esta secuencia de comandos para probar la operación más rápida:

 logTime(); query("SELECT COUNT(id) FROM tbl"); logTime(); query("SELECT MAX(id) FROM tbl"); logTime(); query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1"); logTime(); 

Los resultados son:

  • Count: 36.8418693542479 ms
  • Máx .: 0.241041183472 ms
  • Orden : 0.216960906982 ms

Responda con el método de orden:

 SELECT FLOOR(RAND() * ( SELECT id FROM tbl ORDER BY id DESC LIMIT 1 )) n FROM tbl LIMIT 1 ... SELECT * FROM tbl WHERE id = $result; 

Lo he usado y el trabajo fue hecho la referencia desde aquí

 SELECT * FROM myTable WHERE RAND()<(SELECT ((30/COUNT(*))*10) FROM myTable) ORDER BY RAND() LIMIT 30; 

Cree una función para hacer esto, ¡probablemente sea la mejor respuesta y la respuesta más rápida aquí!

Pros: funciona incluso con Gaps y es extremadamente rápido.

 0){ return $fetch_$data; }else{ rando('','',$max); // Start Over the results returned nothing } }else{ if($max != '0'){ $irand = rand(0,$max); rando('s1',$irand,$max); // Start rando with new random ID to fetch }else{ $query = mysqli_query($sqlConnect, "SELECT `id` FROM `yourtable` ORDER BY `id` DESC LIMIT 0,1"); $fetched_data = mysqli_fetch_assoc($query); $max = $fetched_data['id']; $irand = rand(1,$max); rando('s1',$irand,$max); // Runs rando against the random ID we have selected if data exist will return } } } $your_data = rando(); // Returns listing data for a random entry as a ASSOC ARRAY ?> 

Tenga en cuenta que este código no se ha probado, pero es un concepto que funciona para devolver entradas aleatorias incluso con espacios vacíos. Siempre que los espacios no sean lo suficientemente grandes como para causar un problema de tiempo de carga.

Método rápido y sucio:

 SET @COUNTER=SELECT COUNT(*) FROM your_table; SELECT PrimaryKey FROM your_table LIMIT 1 OFFSET (RAND() * @COUNTER); 

La complejidad de la primera consulta es O (1) para tablas MyISAM.

La segunda consulta acompaña a una tabla de exploración completa. Complejidad = O (n)

Método sucio y rápido:

Mantenga una tabla separada solo para este propósito. También debe insertar las mismas filas en esta tabla cada vez que inserte en la tabla original. Suposición: Sin DELETE.

 CREATE TABLE Aux( MyPK INT AUTO_INCREMENT, PrimaryKey INT ); SET @MaxPK = (SELECT MAX(MyPK) FROM Aux); SET @RandPK = CAST(RANDOM() * @MaxPK, INT) SET @PrimaryKey = (SELECT PrimaryKey FROM Aux WHERE MyPK = @RandPK); 

Si se permiten los DELETE,

 SET @delta = CAST(@RandPK/10, INT); SET @PrimaryKey = (SELECT PrimaryKey FROM Aux WHERE MyPK BETWEEN @RandPK - @delta AND @RandPK + @delta LIMIT 1); 

La complejidad general es O (1).

SELECT DISTINCT * FROM yourTable WHERE 4 = 4 LIMIT 1;