Seleccionar filas aleatorias siempre es complicado y no hay soluciones perfectas que no impliquen algún compromiso. Comprometer el rendimiento, comprometer incluso la distribución aleatoria, o comprometer la posibilidad de seleccionar duplicados, etc.
Como menciona @JakeGould, cualquier solución con ORDER BY RAND()
no escala bien. A medida que aumenta el número de filas en su tabla, el costo de clasificar toda la tabla en una ordenación de archivos empeora cada vez más. Jake tiene razón en que la consulta no se puede almacenar en caché cuando el orden de clasificación es aleatorio. Pero eso no me importa tanto porque normalmente desactivo el caché de consultas de todos modos (tiene sus propios problemas de escalabilidad).
Aquí hay una solución para aleatorizar previamente las filas en la tabla, creando una columna de número de fila y asignando valores consecutivos únicos:
ALTER TABLE products ADD COLUMN rownum INT UNSIGNED, ADD KEY (rownum);
SET @rownum := 0;
UPDATE products SET rownum = (@rownum:[email protected]+1) ORDER BY RAND();
Ahora puede obtener una fila aleatoria mediante una búsqueda de índice, sin ordenando:
SELECT * FROM products WHERE rownum = 1;
O puede obtener la siguiente fila aleatoria:
SELECT * FROM products WHERE rownum = 2;
O puede obtener 10 filas aleatorias a la vez, o cualquier otro número que desee, sin duplicados:
SELECT * FROM products WHERE rownum BETWEEN 11 and 20;
Puede volver a aleatorizar en cualquier momento que desee:
SET @rownum := 0;
UPDATE products SET rownum = (@rownum:[email protected]+1) ORDER BY RAND();
Todavía es costoso hacer la clasificación aleatoria, pero ahora no tiene que hacerlo en cada consulta SELECT. Puede hacerlo en un horario, con suerte fuera de las horas pico.