¿Cómo solicitar una fila aleatoria en SQL?


410

¿Cómo puedo solicitar una fila aleatoria (o tan cerca de lo verdaderamente aleatorio como sea posible) en SQL puro?

  0

que solía hacer siempre esto en php después de resultados de consulta de SQL ... esto es probablemente mucho más rápido para el procesamiento de acuerdo con la solución del límite de 1 apéndice 23 dic. 092009-12-23 20:11:32

  0

[Si SQL Server, puede utilizar un agregado CLR para evitar tipos innecesarios] (http://stackoverflow.com/questions/5210631/selecting-a-distinct-combination-of-2-columns-in-sql/5210706#5210706) 20 mar. 112011-03-20 15:30:55

+2

Parece que no hay una solución de "SQL puro" que se ejecutan en cada dbms ... hay una solución para cada uno de ellos. 05 ago. 142014-08-05 16:11:17

567

ver este mensaje: SQL to Select a random row from a database table . Pasa a través de métodos para hacer esto en MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 y Oracle (el siguiente se copia de ese enlace):

seleccionar una fila al azar con MySQL:

SELECT column FROM table 
ORDER BY RAND() 
LIMIT 1 

Seleccione una fila al azar con PostgreSQL:

SELECT column FROM table 
ORDER BY RANDOM() 
LIMIT 1 

seleccionar una fila aleatoria con Microsoft SQL Server:

SELECT TOP 1 column FROM table 
ORDER BY NEWID() 

Seleccione una fila al azar con IBM DB2

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY 

Seleccione un registro aleatorio con Oracle:

SELECT column FROM 
(SELECT column FROM table 
ORDER BY dbms_random.value) 
WHERE rownum = 1 
+53

+1 para una solución para más de un db. 27 ene. 112011-01-27 22:19:24

+12

-1 para confiar en 'order by rand()' o equivalentes en todos los dbs: |. [también mencionado aquí] (http://stackoverflow.com/questions/19412/how-to-request-a-random-row-in-sql/19568#comment64838_19568). 26 may. 142014-05-26 09:27:04

+8

Hace diez años [alguien dijo] (http://www.titov.net/2005/09/21/do-not-use-order-by-rand-or-how-to-get-random-rows- from-table /) que usar 'ORDER BY RAND()' es incorrecto ... 23 jun. 152015-06-23 06:42:58

  0

ORDER BY NEWID() parece ser marcadamente más lento en SQL Server. Mi consulta es así: seleccione la parte superior C.CustomerId 1000, CL.LoginName del cliente C combinación interna LinkedAccount LA el C.CustomerId = LA.CustomerId combinación interna para nuestros clientes nos CL en C.CustomerId = grupo CL.CustomerId por C .CustomerId, CL.LoginName teniendo count (*)> 1 ordenando por NEWID() Al eliminar la línea "ordenar por NEWID()" se obtienen resultados mucho más rápidos. 26 ago. 152015-08-26 23:02:40

  0

Para SQLite use la función RANDOM(). 22 oct. 152015-10-22 22:34:44

+2

Estas soluciones no tienen escala. Son 'O (n)' con 'n' que es el número de registros en la tabla. Imagine que tiene 1 millón de registros, ¿realmente desea generar 1 millón de números aleatorios o identificadores únicos? Prefiero usar 'COUNT()' e involucrar eso en una nueva expresión 'LIMIT' con un solo número aleatorio. 02 oct. 162016-10-02 11:35:13


58

No sé qué tan eficiente es esto, pero lo he usado antes:

SELECT TOP 1 * FROM MyTable ORDER BY newid() 

Debido GUID son bastante aleatorio, el orden significa que usted obtiene una fila al azar.

  0

Eso es exactamente lo mismo que 'ORDER BY RAND() LIMIT 1' 02 dic. 102010-12-02 05:04:14

+5

Esto también es muy específico de la base de datos ya que usa 'TOP 1' y' newid() '. 08 feb. 112011-02-08 15:02:39

+1

Estoy usando el servidor MS SQL, SELECCIONAR TOP 1 * DE some_table_name ORDER BY NEWID() funcionó muy bien para mí, gracias por el consejo chicos! 10 oct. 102010-10-10 08:12:47

+7

Esta es una mala idea. Este método no usará un índice a menos que cada columna se indexe individualmente. La tabla con 100 millones de registros podría tomar mucho tiempo para obtener un registro. 13 dic. 122012-12-13 19:14:44


0
SELECT * FROM table ORDER BY RAND() LIMIT 1 
  0

Hace diez años (2005) alguien dijo [dijo] (http://www.titov.net/2005/09/21/do-not-use-order-by-rand-or-how-to-get-random -rows-from-table /) que usar 'ORDER BY RAND()' es incorrecto ... 23 jun. 152015-06-23 07:09:13


12

Usted no dijo qué servidor está utilizando. En versiones anteriores de SQL Server, puede utilizar esto:

select top 1 * from mytable order by newid() 

En SQL Server 2005 y hasta, puede utilizar TABLESAMPLE para obtener una muestra aleatoria que es repetible:

SELECT FirstName, LastName 
FROM Contact 
TABLESAMPLE (1 ROWS) ; 
+8

MSDN dice que se prefiere newid() sobre tablesample para resultados realmente aleatorios: http://msdn.microsoft.com/en-us/library/ms189108.aspx 10 nov. 082008-11-10 23:02:50

+5

@Andrew Hedges: ORDEN POR NEWID() es demasiado costoso 04 nov. 102010-11-04 14:56:57


2

La mejor manera es poner un valor aleatorio en una nueva columna sólo para ese fin, y usar algo como esto (código pseudo + SQL):

randomNo = random() 
execSql("SELECT TOP 1 * FROM MyTable WHERE MyTable.Randomness > $randomNo") 

Esta es la solución empleada por el código MediaWiki. Por supuesto, existe cierto sesgo en contra de valores más pequeños, pero encontraron que era suficiente para envolver el valor aleatorio a cero cuando no se obtienen las filas.

newid() la solución puede requerir un escaneo completo de la tabla para que a cada fila se le pueda asignar un nuevo guid, que será mucho menos eficaz.

rand() la solución puede no funcionar en absoluto (es decir, con MSSQL) porque la función se evaluará solo una vez, y cada fila se le asignará el mismo número "aleatorio".

+1

Envolviendo cuando obtiene 0 resultados proporciona una muestra probadamente aleatoria (no solo "suficientemente buena"). Esta solución * casi * se adapta a consultas de varias filas (piense en "mezcla aleatoria"). El problema es que los resultados tienden a seleccionarse en los mismos grupos repetidamente. Para evitar esto, necesitaría volver a distribuir los números aleatorios que acaba de utilizar. Puedes hacer trampa haciendo un seguimiento de randomNo y estableciéndolo en max (aleatoriedad) de los resultados, pero luego p (fila i en la consulta 1 Y fila i en la consulta 2) == 0, lo cual no es justo. Déjame hacer algunas matemáticas, y me pondré en contacto contigo con un esquema verdaderamente justo. 29 oct. 092009-10-29 09:25:40


168

Soluciones como Jeremies:

SELECT * FROM table ORDER BY RAND() LIMIT 1 

trabajo, pero necesitan una exploración secuencial de toda la tabla (ya que el valor aleatorio asociado a cada fila debe ser calculada - para que el más pequeño se puede determinar) , que puede ser bastante lento incluso para mesas de tamaño mediano.Mi recomendación sería utilizar algún tipo de columna numérica indexado (muchas mesas tienen estos como sus claves primarias), y luego escribir algo como:

SELECT * FROM table WHERE num_value >= RAND() * 
    (SELECT MAX (num_value) FROM table) 
ORDER BY num_value LIMIT 1 

Esto funciona en tiempo logarítmico, independientemente del tamaño de la tabla, si num_value está indexado Una advertencia: esto supone que num_value se distribuye por igual en el rango 0..MAX(num_value). Si su conjunto de datos se desvía fuertemente de esta suposición, obtendrá resultados sesgados (algunas filas aparecerán con más frecuencia que otras).

+7

La segunda sugerencia no es aleatoria. No puede predecir la fila que se va a recoger, pero si tuviera que apostar, apostaría a la segunda fila. Y nunca apostaría en la última fila, es menos probable que sea escogido sea cual sea la distribución de su num_valor y cuán grande es su mesa. 14 nov. 102010-11-14 17:38:31

+1

Sé que, por lo general, las funciones RAND() no son de muy alta calidad, pero aparte de eso, ¿pueden explicar por qué la selección no sería aleatoria? 16 nov. 102010-11-16 11:43:21

  0

También creo que será tan aleatorio como 'RAND()' puede ser. 17 nov. 102010-11-17 22:59:56

  0

¿Puedes explicar qué es una 'columna numérica indexada'? ¿Es como hacer que la clave primaria aumente automáticamente de 0 al máximo actual? 22 mar. 112011-03-22 15:14:30

+11

El primero es INCORRECTO en SQL Server. La función RAND() se invoca solo una vez por consulta, no una vez por fila. Por lo tanto, siempre selecciona la primera fila (pruébelo). 08 feb. 122012-02-08 21:49:32

+3

El segundo también supone que se tienen en cuenta todas las filas: es posible que elija una fila que se ha eliminado. 20 feb. 122012-02-20 13:56:52

+3

@ Sam.Rueby En realidad, num_value> = RAND() ... limit 1 asegura que las filas vacías se omitirán hasta que encuentre una fila existente. 22 jul. 122012-07-22 13:51:44

  0

@ Cd-MaN: Buena solución. ¿Existe también una manera eficiente de tomar una muestra aleatoria de tamaño 'n' en lugar de' 1'? ('LIMIT n' daría como resultado entradas contiguas) 06 ago. 122012-08-06 12:56:05

  0

Utilicé mi clave principal como num_value, pero al ejecutar' EXPLAIN' dice que todavía está pasando por TODAS las filas ... 20 jun. 132013-06-20 14:34:09

  0

La segunda solución parece tan prometedora, pero no funcionó t funciona bien En una mesa con 60,000 registros siempre escogió números bajos. Casi siempre por debajo de 1000. No estoy seguro de por qué. Esto es lo que realmente funcionó y fue muy aleatorio: SELECCIONAR * FROM preguntas AS t1 UNIRSE (SELECCIONAR RAND() * (SELECCIONAR MAX (id) DESDE preguntas) AS max_id) AS t2 DONDE t1.id> = t2.max_id ORDER BY id LIMIT 1 28 abr. 172017-04-28 03:46:25


0

Tengo que estar de acuerdo con CD-MaN: Usar "ORDER BY RAND()" funcionará muy bien para las tablas pequeñas o cuando haga su SELECT solo unas pocas veces.

También uso la técnica "num_value> = RAND() * ...", y si realmente quiero tener resultados aleatorios, tengo una columna especial "aleatoria" en la tabla que actualizo una vez al día o más . Esa ejecución única de ACTUALIZACIÓN llevará algún tiempo (especialmente porque tendrá que tener un índice en esa columna), pero es mucho más rápido que crear números aleatorios para cada fila cada vez que se ejecuta la selección.


3

Para SQL Server 2005 y 2008, si queremos una muestra aleatoria de filas individuales (de Books Online):

SELECT * FROM Sales.SalesOrderDetail 
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float) 
/CAST (0x7fffffff AS int) 

0

tener cuidado porque TABLESAMPLE en realidad no devolvió una muestra aleatoria de filas. Dirige su consulta para ver una muestra aleatoria de las páginas de 8 KB que componen su fila. Entonces, su consulta se ejecuta contra los datos contenidos en estas páginas. Debido a la forma en que los datos se pueden agrupar en estas páginas (orden de inserción, etc.), esto podría generar datos que en realidad no son una muestra aleatoria.

Ver: http://www.mssqltips.com/tip.asp?tip=1308

Esta página de MSDN para TABLESAMPLE incluye un ejemplo de cómo generar una muestra aleatoria de los datos podía comprender.

http://msdn.microsoft.com/en-us/library/ms189108.aspx


9

Para SQL Server

newid()/orden por funcionará, pero va a ser muy caro para grandes conjuntos de resultados, ya que tiene que generar un identificador para cada fila, y luego ordenarlos.

TABLESAMPLE() es bueno desde el punto de vista del rendimiento, pero obtendrá una agrupación de resultados (se devolverán todas las filas de una página).

Para una mejor muestra aleatoria real, la mejor manera es filtrar las filas al azar. He encontrado el siguiente código de ejemplo en el artículo de SQL Server Libros en Limiting Results Sets by Using TABLESAMPLE:

Si realmente quieres una muestra aleatoria de filas individuales, modifique la consulta para filtro cabo filas al azar, en lugar de usando TABLESAMPLE . Por ejemplo, el siguiente consulta utiliza la función NEWID para volver aproximadamente un por ciento de las filas de la tabla Sales.SalesOrderDetail:

SELECT * FROM Sales.SalesOrderDetail 
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float) 
      /CAST (0x7fffffff AS int) 

La columna SalesOrderID está incluido en la expresión CHECKSUM para que NEWID() evalúa una vez por fila a para lograr el muestreo por fila. El REPARTO expresión (CHECKSUM (NEWID(), SalesOrderID) & 0x7fffffff AS flotador/ CAST (0x7fffffff AS int) se evalúa como un valor flotante aleatorio entre 0 y 1.

Cuando se ejecuta en una tabla con 1.000.000 de filas, aquí están mis resultados:..

SET STATISTICS TIME ON 
SET STATISTICS IO ON 

/* newid() 
    rows returned: 10000 
    logical reads: 3359 
    CPU time: 3312 ms 
    elapsed time = 3359 ms 
*/ 
SELECT TOP 1 PERCENT Number 
FROM Numbers 
ORDER BY newid() 

/* TABLESAMPLE 
    rows returned: 9269 (varies) 
    logical reads: 32 
    CPU time: 0 ms 
    elapsed time: 5 ms 
*/ 
SELECT Number 
FROM Numbers 
TABLESAMPLE (1 PERCENT) 

/* Filter 
    rows returned: 9994 (varies) 
    logical reads: 3359 
    CPU time: 641 ms 
    elapsed time: 627 ms 
*/  
SELECT Number 
FROM Numbers 
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float) 
      /CAST (0x7fffffff AS int) 

SET STATISTICS IO OFF 
SET STATISTICS TIME OFF 

Si usted puede conseguir lejos con el uso TABLESAMPLE, se le dará el mejor rendimiento lo contrario usar la newid()/método de filtro newid()/orden por el debería ser último recurso si tiene un gran conjunto de resultados.


1

La mayoría de las soluciones aquí intentan evitar la clasificación, pero aún así es necesario realizar un escaneo secuencial en una tabla.

También hay una forma de evitar el escaneo secuencial cambiando al escaneo de índice. Si conoce el valor del índice de su fila al azar, puede obtener el resultado casi de manera instantánea. El problema es cómo adivinar un valor de índice.

La siguiente solución funciona en PostgreSQL 8.4:

explain analyze select * from cms_refs where rec_id in 
    (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
    from generate_series(1,10)) 
    limit 1; 

I anterior solución que supongo 10 diferentes valores de índice al azar de la gama 0 .. [último valor de id].

El número 10 es arbitrario: puede usar 100 o 1000, ya que (sorprendentemente) no tiene un gran impacto en el tiempo de respuesta.

También hay un problema: si tiene pocos ID , puede perder. La solución es tiene un plan de copia de seguridad :) En este caso, una consulta de orden antiguo puro por random(). Cuando Identificación del combinado se ve así:

explain analyze select * from cms_refs where rec_id in 
    (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
    from generate_series(1,10)) 
    union all (select * from cms_refs order by random() limit 1) 
    limit 1; 

No es la unión cláusula ALL. ¡En este caso, si la primera parte devuelve datos, el segundo NUNCA se ejecutará!


1

Atrasado, pero llegó aquí a través de Google, así que por el bien de la posteridad, agregaré una solución alternativa.

Otro enfoque es utilizar TOP dos veces, con pedidos alternativos. No sé si es "SQL puro", porque usa una variable en el TOP, pero funciona en SQL Server 2008. Aquí hay un ejemplo que uso contra una tabla de palabras del diccionario, si quiero una palabra al azar.

SELECT TOP 1 
    word 
FROM (
    SELECT TOP(@idx) 
    word 
    FROM 
    dbo.DictionaryAbridged WITH(NOLOCK) 
    ORDER BY 
    word DESC 
) AS D 
ORDER BY 
    word ASC 

Por supuesto, @idx es algún entero generada de forma aleatoria que varía de 1 a COUNT (*) en la tabla de destino, inclusive. Si su columna está indexada, también se beneficiará de ella. Otra ventaja es que puede usarlo en una función, ya que NEWID() no está permitido.

Por último, la consulta anterior se ejecuta en aproximadamente 1/10 del tiempo de ejecución de un NEWID() - tipo de consulta en la misma tabla. YYMV.


20
ORDER BY NEWID() 

toma 7.4 milliseconds

WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table) 

toma 0.0065 milliseconds!

Iré definitivamente con el último método.

+1

La segunda opción no elegirá la última fila. No sé por qué, solo lo señalo. 08 oct. 142014-10-08 23:31:26

+4

@Voldemort: 'rand()' devuelve un número de coma flotante 'n' donde' 0 <n <1'. Suponiendo que 'num_value' es un entero, el valor de retorno de' rand() * max (num_value) 'también será forzado a un entero, truncando así cualquier cosa después del punto decimal. Por lo tanto, 'rand() * max (num_value)' ** siempre ** será menor que 'max (num_value)', por lo que nunca se seleccionará la última fila. 18 feb. 152015-02-18 14:57:18

  0

No seré eficiente si mis datos se eliminan con frecuencia; si encuentro un hueco, tendré que volver a ejecutar toda la consulta. 22 may. 172017-05-22 05:26:38


4

Si es posible, utilice instrucciones almacenadas para evitar la ineficacia de ambos índices en RND() y crear un campo de número de registro.

 
PREPARE RandomRecord FROM "SELECT * FROM table LIMIT ?,1"; 
SET @n=FLOOR(RAND()*(SELECT COUNT(*) FROM table)); 
EXECUTE RandomRecord USING @n; 
  0

Esta solución también se encarga de devolver las filas aleatorias cuando el valor numérico indexado utilizado en la cláusula where anterior no se distribuye por igual; así que incluso si lleva casi el mismo tiempo (constante) que usar where id_value> = RAND() * MAX (id_value), es mejor. 08 feb. 112011-02-08 22:33:03

  0

Por lo que puedo decir, esto no se ejecuta en tiempo constante, se ejecuta en tiempo lineal. En el peor de los casos, @n es igual al número de filas en la tabla, y "SELECT * FROM table LIMIT?, 1" evalúa @n - 1 filas hasta que llega al último. 21 sep. 142014-09-21 05:05:45


0

Parece que muchas de las ideas que figuran todavía utilizan el pedido

Sin embargo, si se utiliza una tabla temporal, que son capaces de asignar un índice aleatorio (al igual que muchas de las soluciones han sugerido), y a continuación, coger la primera que es mayor que un número arbitrario entre 0 y 1.

por ejemplo (para DB2):

WITH TEMP AS (
SELECT COMLUMN, RAND() AS IDX FROM TABLE) 
SELECT COLUMN FROM TABLE WHERE IDX > .5 
FETCH FIRST 1 ROW ONLY 
+2

Después de considerar esta solución, he encontrado un error fundamental en mi lógica. Esto devolvería consistentemente los mismos pequeños valores de configuración, cerca del comienzo de la tabla, porque supongo que si hubiera una distribución uniforme entre 0 y 1, hay un 50% de posibilidades de que la primera fila cumpla con ese criterio. 31 ene. 112011-01-31 22:59:50


1

también puede tratar de usarFunción.

Simplemente escriba su consulta y use la orden por la función new id(). Es bastante aleatorio.


2

Como se señala en el comentario de @ BillKarwin sobre la respuesta de @ CNU ...

Cuando se combina con un límite, he encontrado que funciona mucho mejor (al menos con PostgreSQL 9.1) para unirse con un orden aleatorio en lugar de ordenar directamente las filas reales: por ejemplo

 
SELECT * FROM tbl_post AS t 
JOIN ... 
JOIN (SELECT id, CAST(-2147483648 * RANDOM() AS integer) AS rand 
     FROM tbl_post 
     WHERE create_time >= 1349928000 
    ) r ON r.id = t.id 
WHERE create_time >= 1349928000 AND ... 
ORDER BY r.rand 
LIMIT 100 

Sólo asegúrese de que la 'r' genera un valor '' rand por cada valor de clave posible en la consulta compleja que está unida con ella, pero aún limitar el número de filas de 'r' cuando sea posible.

El CAST como entero es especialmente útil para PostgreSQL 9.2 que tiene una optimización de clasificación específica para tipos flotantes enteros y de precisión única.


1

Para MySQL para obtener registro aleatorio

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 

Más detalles http://jan.kneschke.de/projects/mysql/order-by-rand/

  0

Después de probar muchas de las respuestas, creo que esta es la mejor. Parece ser rápido y elige un buen número aleatorio cada vez. Parece similar a la segunda sugerencia de @GreyPanther, pero esta respuesta selecciona más números aleatorios. 28 abr. 172017-04-28 05:30:10


0

Una manera simple y eficiente de http://akinas.com/pages/en/blog/mysql_random_row/

SET @i = (SELECT FLOOR(RAND() * COUNT(*)) FROM table); PREPARE get_stmt FROM 'SELECT * FROM table LIMIT ?, 1'; EXECUTE get_stmt USING @i; 

1

no acababa de ver esta variación en la respuesta. Tenía una restricción adicional donde necesitaba, dada una semilla inicial, seleccionar el mismo conjunto de filas cada vez.

Para MS SQL:

ejemplo mínima:

select top 10 percent * 
from table_name 
order by rand(checksum(*)) 

Normalizado tiempo de ejecución: 1,00

NEWID() ejemplo:

select top 10 percent * 
from table_name 
order by newid() 

tiempo de ejecución normalizado: 1,02

NewId() es insignificantemente más lento que rand(checksum(*)), por lo que es posible que no desee utilizarlo contra grandes conjuntos de registros.

Selección con el germen inicial:

declare @seed int 
set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */ 

select top 10 percent * 
from table_name 
order by rand(checksum(*) % seed) /* any other math function here */ 

Si es necesario seleccionar el mismo conjunto dado una semilla, esto parece funcionar.


0

Existe una mejor solución para Oracle en lugar de usar dbms_random.value, mientras que requiere un escaneo completo para ordenar filas por dbms_random.value y es bastante lento para tablas grandes.

Uso este lugar:

SELECT * 
FROM employee sample(1) 
WHERE rownum=1 

1

En MSSQL (probado en 11.0.5569) usando

SELECT TOP 100 * FROM employee ORDER BY CRYPT_GEN_RANDOM(10) 

es significativamente más rápido que

SELECT TOP 100 * FROM employee ORDER BY NEWID() 

0

Para Firebird:

Select FIRST 1 column from table ORDER BY RAND() 

2

Insted de using RAND(), as it is not encouraged, se puede conseguir simplemente Identificación max (= Max):

SELECT MAX(ID) FROM TABLE; 

obtener un aleatorio entre 1..Max (= My_Generated_Random)

My_Generated_Random = rand_in_your_programming_lang_function(1..Max); 

y luego ejecutar este SQL:

SELECT ID FROM TABLE WHERE ID >= My_Generated_Random ORDER BY ID LIMIT 1 

Tenga en cuenta que comprobará si las filas que Ids tienen el valor EQUAL o SUPERIOR al valor elegido. También es posible buscar la fila hacia abajo en la tabla, y obtener un ID igual o inferior a la My_Generated_Random, a continuación, modificar la consulta como la siguiente:

SELECT ID FROM TABLE WHERE ID <= My_Generated_Random ORDER BY ID DESC LIMIT 1 

1

En SQL Server puede combinar TABLESAMPLE con NEWID() para obtener aleatoriedad bastante buena y aún tener velocidad. Esto es especialmente útil si realmente solo quiere 1 o un pequeño número de filas.

SELECT TOP 1 * FROM [table] 
TABLESAMPLE (500 ROWS) 
ORDER BY NEWID()