¿Cuál es la mejor (y más rápida) forma de recuperar una fila aleatoria usando Linq to SQL cuando tengo una condición, por ejemplo, algún campo debe ser verdadero?
c#
.net
linq-to-sql
Julien Poulin
fuente
fuente
Respuestas:
Puede hacer esto en la base de datos, utilizando una UDF falsa; en una clase parcial, agregue un método al contexto de datos:
Entonces solo
order by ctx.Random()
; esto hará un pedido aleatorio en el SQL-Server cortesía deNEWID()
. es decirTenga en cuenta que esto solo es adecuado para mesas de tamaño pequeño a mediano; para tablas grandes, tendrá un impacto en el rendimiento en el servidor y será más eficiente encontrar el número de filas (
Count
) y luego elegir una al azar (Skip/First
).para el enfoque de conteo:
fuente
Otra muestra de Entity Framework:
Esto no funciona con LINQ to SQL. El
OrderBy
simplemente se está eliminando.fuente
EDITAR: Acabo de notar que esto es LINQ to SQL, no LINQ to Objects. Utilice el código de Marc para que la base de datos haga esto por usted. Dejé esta respuesta aquí como un posible punto de interés para LINQ to Objects.
Por extraño que parezca, en realidad no es necesario contarlo. Sin embargo, necesita buscar todos los elementos a menos que obtenga el recuento.
Lo que puede hacer es mantener la idea de un valor "actual" y el recuento actual. Cuando obtenga el siguiente valor, tome un número aleatorio y reemplace el "actual" con "nuevo" con una probabilidad de 1 / n donde n es el recuento.
Entonces, cuando lee el primer valor, siempre lo convierte en el valor "actual". Cuando lea el segundo valor, puede convertirlo en el valor actual (probabilidad 1/2). Cuando lea el tercer valor, es posible que convertirlo en el valor actual (probabilidad 1/3), etc. Cuando se haya quedado sin datos, el valor actual es aleatorio de todos los que leyó, con probabilidad uniforme.
Para aplicar eso con una condición, simplemente ignore todo lo que no cumpla con la condición. La forma más sencilla de hacerlo es considerar solo la secuencia de "coincidencia" para empezar, aplicando primero una cláusula Where.
Aquí hay una implementación rápida. Yo creo que está bien ...
fuente
current
será siempre estar configurado en el primer elemento. En la segunda iteración, hay un cambio del 50% que se establecerá en el segundo elemento. En la tercera iteración, hay un 33% de posibilidades de que se establezca en el tercer elemento. Agregar una declaración de interrupción significaría que siempre saldría después de leer el primer elemento, por lo que no es aleatorio en absoluto.Una forma de lograrlo de manera eficiente es agregar una columna a sus datos
Shuffle
que se completa con un int aleatorio (a medida que se crea cada registro).La consulta parcial para acceder a la tabla en orden aleatorio es ...
Esto hace una operación XOR en la base de datos y ordena los resultados de ese XOR.
Ventajas: -
Este es el enfoque utilizado por mi sistema de automatización del hogar para aleatorizar listas de reproducción. Recoge una nueva semilla cada día dando un orden constante durante el día (lo que permite una fácil pausa / reanudación) pero una nueva mirada a cada lista de reproducción cada nuevo día.
fuente
result = result.OrderBy(s => s.Shuffle ^ seed);
(es decir, no es necesario implementar el XOR a través de los operadores ~, & y |).si desea obtener, por ejemplo,
var count = 16
filas aleatorias de la tabla, puede escribiraquí usé EF, y la tabla es un Dbset
fuente
Si el propósito de obtener filas aleatorias es el muestreo, he hablado muy brevemente aquí sobre un buen enfoque de Larson et al., El equipo de investigación de Microsoft, donde han desarrollado un marco de muestreo para Sql Server utilizando vistas materializadas. También hay un enlace al documento real.
fuente
Explicación: Al insertar el guid (que es aleatorio), el orden con orderby sería aleatorio.
fuente
Vine aquí preguntándome cómo obtener algunas páginas aleatorias de un pequeño número de ellas, para que cada usuario obtenga 3 páginas aleatorias diferentes.
Esta es mi solución final, trabajando consultando con LINQ contra una lista de páginas en Sharepoint 2010. Está en Visual Basic, lo siento: p
Probablemente debería obtener algunos perfiles antes de consultar una gran cantidad de resultados, pero es perfecto para mi propósito.
fuente
Tengo una consulta de función aleatoria contra
DataTable
s:fuente
El siguiente ejemplo llamará a la fuente para recuperar un recuento y luego aplicará una expresión de omisión en la fuente con un número entre 0 y n. El segundo método aplicará orden utilizando el objeto aleatorio (que ordenará todo en la memoria) y seleccionará el número pasado a la llamada al método.
fuente
utilizo este método para tomar noticias aleatorias y funciona bien;)
fuente
Usar LINQ to SQL en LINQPad como se ven las declaraciones de C #
El SQL generado es
fuente
Si usa LINQPad , cambie al modo de programa C # y haga lo siguiente:
fuente
Seleccionar 2 filas al azar
fuente
Para agregar a la solución de Marc Gravell. Si no está trabajando con la clase de contexto de datos en sí (porque lo utiliza como proxy de alguna manera, por ejemplo, para falsificar el contexto de datos con fines de prueba), no puede usar la UDF definida directamente: no se compilará en SQL porque no la está usando en un subclase o clase parcial de su clase de contexto de datos reales.
Una solución para este problema es crear una función Randomize en su proxy, alimentándola con la consulta que desea que sea aleatoria:
Así es como lo usaría en su código:
Para ser completo, así es como implementar esto en el contexto de datos FALSO (que usa en entidades de memoria):
fuente