¿Cómo tomo una muestra aleatoria simple eficiente en SQL? La base de datos en cuestión está ejecutando MySQL; mi tabla tiene al menos 200,000 filas y quiero una muestra aleatoria simple de aproximadamente 10,000.
La respuesta "obvia" es:
SELECT * FROM table ORDER BY RAND() LIMIT 10000
Para tablas grandes, eso es demasiado lento: llama RAND()
a cada fila (que ya la coloca en O (n)) y las ordena, convirtiéndola en O (n lg n) en el mejor de los casos. ¿Hay alguna forma de hacer esto más rápido que O (n)?
Nota : Como Andrew Mao señala en los comentarios, si está usando este enfoque en SQL Server, debe usar la función T-SQL NEWID()
, porque RAND () puede devolver el mismo valor para todas las filas .
EDITAR: 5 AÑOS DESPUÉS
Me encontré con este problema nuevamente con una tabla más grande y terminé usando una versión de la solución de @ ignorant, con dos ajustes:
- Muestree las filas a 2-5 veces el tamaño de muestra deseado, a bajo costo
ORDER BY RAND()
- Guarde el resultado de
RAND()
en una columna indexada en cada inserción / actualización. (Si su conjunto de datos no tiene muchas actualizaciones, es posible que deba encontrar otra forma de mantener actualizada esta columna).
Para tomar una muestra de 1000 elementos de una tabla, cuento las filas y muestre el resultado hasta, en promedio, 10,000 filas con la columna frozen_rand:
SELECT COUNT(*) FROM table; -- Use this to determine rand_low and rand_high
SELECT *
FROM table
WHERE frozen_rand BETWEEN %(rand_low)s AND %(rand_high)s
ORDER BY RAND() LIMIT 1000
(Mi implementación real implica más trabajo para asegurarme de que no muestre menos y para ajustar manualmente rand_high, pero la idea básica es "reducir aleatoriamente su N a unos pocos miles").
Si bien esto hace algunos sacrificios, me permite muestrear la base de datos utilizando un escaneo de índice, hasta que sea lo suficientemente pequeño como para ORDER BY RAND()
volver a hacerlo .
RAND()
devuelve el mismo valor en cada llamada posterior.