¿Cómo se toma una muestra aleatoria simple eficiente en SQL? La base de datos en cuestión ejecuta MySQL; mi tabla tiene al menos 200,000 filas, y quiero una muestra aleatoria simple de aproximadamente 10,000.Muestras aleatorias simples de una base de datos SQL
La respuesta "obvia" es:
SELECT * FROM table ORDER BY RAND() LIMIT 10000
Para tablas grandes, eso es demasiado lento: se llama RAND() para cada fila (que ya pone en O (n)), y los ordena , convirtiéndolo en O (n lg n) en el mejor de los casos. ¿Hay alguna manera de hacer esto más rápido que O (n)?
Nota: Como Andrew Mao señala en los comentarios, si usted está usando este enfoque en SQL Server, debe utilizar la función NEWID T-SQL(), porque RAND() may return the same value for all rows.
EDIT: 5 años más tarde
me encontré con este problema de nuevo con una mesa más grande, y terminó con una versión de @ solución de ignorantes, con dos ajustes:
- Muestra las filas a 2-5x 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 es muy pesado, es posible que deba encontrar otra forma de mantener fresca esta columna.)
Para tomar una muestra de 1000 elementos de una tabla, cuento las filas y la muestra el resultado hasta, en promedio, 10.000 filas con la columna de la 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 aplicación efectiva implica más trabajo para asegurarse de que no lo hago undersample, y para envolver manualmente rand_high alrededor, pero la idea básica es "cortar aleatoriamente tu N a unos pocos miles")
Si bien esto hace algunos sacrificios, me permite baje la base de datos usando un escaneo de índice, hasta que sea lo suficientemente pequeño como para ORDER BY RAND() nuevamente.
que ni siquiera funciona en el servidor SQL porque 'RAND()' devuelve el mismo valor cada llamada posterior. –
Buen punto: añadiré una nota que los usuarios de SQL Server deberían usar ORDER BY NEWID() en su lugar. – ojrac
Todavía es terriblemente ineficiente porque tiene que ordenar todos los datos. Una técnica de muestreo aleatorio para un porcentaje es mejor, pero incluso después de leer un montón de publicaciones aquí, no he encontrado una solución aceptable que sea lo suficientemente aleatoria. –