2009-12-08 17 views
7

Duplicar posibles:
MySQL: Alternatives to ORDER BY RAND()ORDER BY RAND() alternativa

Actualmente tengo una consulta que termina ORDER BY RAND(HOUR(NOW())) LIMIT 40 para obtener 40 resultados aleatorios. La lista de resultados cambia cada hora.

Esto elimina la caché de consultas, lo que perjudica el rendimiento.

¿Puede sugerir una forma alternativa de obtener un conjunto aleatorio (ish) de resultados que cambien cada cierto tiempo? No tiene que ser cada horas y no tiene que ser totalmente aleatorio.

yo preferiría un resultado aleatorio, en lugar de clasificación en un campo arbitrario en la tabla, pero voy a hacerlo como último recurso ...

(esta es una lista de nuevos productos que yo quiero barajar un poco de vez en cuando).

+1

¿Podría proporcionarnos alguna información sobre en qué está codificando esto? Sugeriría hacer esto en código en lugar de sql. – jamesaharvey

+0

¿Inner ordenó 'SELECT'? –

+0

¿Podría simplemente almacenarlo en caché en el nivel de la aplicación? – Greg

Respuesta

3

creo que la mejor forma de hacerlo es descargar identificadores de productos a su capa media, elige al azar 40 valores cuando se necesita (una vez por hora o por cada petición) y utilícelos en la consulta: product_id in (@id_1, @id_2, ..., @id_40).

+0

+1 Esta suele ser una buena solución, a menos que @rikh ejecute Amazon o eBay (es decir, millones de productos). Tener los ID en la memoria también puede ser útil para otras optimizaciones. – Seth

5

Va a matar la memoria caché porque espera un resultado diferente cada vez. No hay forma de que pueda almacenar en caché un conjunto aleatorio de valores. Si desea almacenar en caché un grupo de resultados, guarde en caché un gran conjunto aleatorio de valores y, luego, dentro de las subsecciones del tiempo en que vaya a utilizar esos valores, haga una captura aleatoria dentro del conjunto más pequeño [fuera de sql].

+0

Bueno, solo quiero que cambie cada hora más o menos, así que durante la hora se arreglará. Esto es lo que produce mi consulta actual, con la desventaja de utilizar rand() que impide que los resultados se almacenen en caché. –

+0

Buen punto: no es necesario depender de * MySQL * caché; p.ej. memcached u otro caché de nivel de aplicación estaría bien. – Piskvor

0

Una forma de lograrlo es mezclar los objetos para mapear los datos. Si no asigna los datos a objetos, podría mezclar la matriz de resultados de la base de datos. No sé si funcionará mejor o no, pero al menos obtendrá los beneficios del caché de consultas como usted menciona.

También podría generar una secuencia aleatoria de 1 a n, e indexar la matriz de resultados (o matriz de objetos) con esos.

1

es posible que tenga una columna con valores aleatorios que actualice cada hora.

6

Si usted tiene una columna de ID que es mejor hacer un:

-- create a variable to hold the random number 
SET @rownum := SELECT count(*) FROM table; 
SET @row := (SELECT CEIL((rand() * @rownum)); 

-- use the random number to select on the id column 
SELECT * from tablle WHERE id = @row; 

La lógica de selección del número de identificación al azar puede ser movida a nivel de aplicación.

SELECT * FROM table ORDER BY RAND LIMIT 40 

es muy ineficiente ya que MySQL procesará todos los registros de la tabla que realizan una mesa de exploración completa en todas las filas, ordenar de forma aleatoria.

+1

La tabla podría tener ID faltadas en algún lugar en el medio, por lo que la selección correcta sería al final: 'SELECT * from tablle WHERE id> = @row LIMIT 1;' – cephuo

0

calcule la hora actual en su código PHP y páselo a su consulta. esto dará como resultado un valor estático que se puede almacenar en caché.

tenga en cuenta que es posible que también tenga un error oculto. ya que solo está tomando la hora, solo tiene 24 valores diferentes, que se repetirán todos los días. lo que significa que lo que se muestra hoy a la 1 pm también será igual a lo que muestra mañana a las 6. Es posible que desee cambiar eso.

+1

la hora se está utilizando como una semilla para el azar generador de números Sí, sé que obtengo los mismos resultados a las 2 p.m. todos los días, pero eso está bien (a menos que la lista de productos cambie de alguna manera) –

0

No luche con el caché-- ¡exíjalo!

Escriba su consulta tal como es (o incluso más simple). Luego, en su código, guarde en caché los resultados, estableciendo un vencimiento de caché por 1 hora.Si está utilizando una capa de almacenamiento en caché, como memcached, está configurado. Si no es así, se puede construir un bastante simple:

[pseudocode] 
global cache[24] 
h = Time.hour 
if (cache[h] == null) { 
    cache[h] = .. run your query 
} 
return cache[h]; 
0

Si solo necesita un nuevo conjunto de datos aleatorios una vez por hora, no acceda a la base de datos; guarde los resultados en la capa de almacenamiento en caché de la aplicación (o, si no tiene uno, simplemente colóquelo en archivo temporal de algún tipo). Query Cache es útil, pero si nunca necesita ejecutar una consulta, aún mejor ...

1

Esto va a ser una consulta bastante desagradable si necesita ordenar un gran conjunto de datos en un orden aleatorio (que realmente requiere un tipo), luego descarta todos menos los primeros 40 registros.

Una mejor solución sería simplemente elegir 40 registros aleatorios. Hay muchas maneras de hacerlo y generalmente depende de tener claves que estén distribuidas uniformemente.

Otra opción es elegir los 40 registros aleatorios en un trabajo por lotes que solo se ejecuta una vez por hora (o lo que sea) y luego recordar cuáles son.