2009-12-08 24 views
7

Eventuali duplicati:
MySQL: Alternatives to ORDER BY RAND()ORDER BY RAND() alternativa

Al momento ho una domanda che si conclude ORDER BY RAND(HOUR(NOW())) LIMIT 40 per ottenere 40 risultati casuali. L'elenco dei risultati cambia ogni ora.

Questo uccide la cache della query, che è dannosa per le prestazioni.

Puoi suggerire un modo alternativo di ottenere un insieme casuale di risultati che cambia di volta in volta? Non deve essere ogni ora e non deve essere assolutamente casuale.

io preferirei un risultato casuale, piuttosto che l'ordinamento su un campo arbitrario nella tabella, ma lo farò come ultima risorsa ...

(Questa è una lista di nuovi prodotti che voglio mescola un po 'di tanto in tanto).

+1

Puoi fornire qualche informazione su cosa stai codificando? Suggerirei di farlo in codice invece che in sql. – jamesaharvey

+0

"SELECT" ordinato interno? –

+0

Potrebbe semplicemente memorizzarlo nella cache a livello di applicazione? – Greg

risposta

3

Penso che il modo migliore è quello di scaricare gli identificatori di prodotto al vostro strato intermedio, scegliere a caso 40 valori quando si ha bisogno (una volta ogni ora o per ogni richiesta) e usali nella query: product_id in (@id_1, @id_2, ..., @id_40).

+0

+1 Questa è spesso una buona soluzione, a meno che @rikh stia eseguendo Amazon o eBay (ad esempio, milioni di prodotti). Avere gli ID in memoria potrebbe essere utile anche per altre ottimizzazioni. – Seth

5

L'intenzione di uccidere la cache perché si prevede un set di risultati diverso ogni volta. Non c'è modo di memorizzare una serie casuale di valori. Se si desidera memorizzare nella cache un gruppo di risultati, memorizzare in cache un grande insieme casuale di valori, quindi all'interno delle sottosezioni del tempo in cui si utilizzeranno tali valori eseguire una cattura casuale all'interno del set più piccolo [all'esterno di sql].

+0

Beh, voglio solo che cambi ogni ora o così, quindi durante l'ora verrà corretto. Questo è ciò che produce la mia query corrente, con il lato negativo dell'uso di rand() che impedisce la memorizzazione dei risultati. –

+0

Buon punto: non è necessario dipendere dalla * cache di MySQL *; per esempio. memcached o un'altra cache del livello dell'applicazione andrebbe bene. – Piskvor

0

Un modo per raggiungerlo è mescolare gli oggetti su cui si mappano i dati. Se non si associano i dati agli oggetti, è possibile mescolare l'array dei risultati dal database. Non so se questo si comporterà meglio o no, ma almeno trarrai i benefici dalla cache delle query come dici.

È anche possibile generare una sequenza casuale da 1 a n e indicizzare l'array di risultati (o l'array di oggetti) con quelli.

1

potresti avere una colonna con valori casuali che aggiorni ogni ora.

6

Se si dispone di una colonna ID è meglio fare 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 logica di selezionare il numero ID casuale può essere mossa al livello di applicazione.

SELECT * FROM table ORDER BY RAND LIMIT 40 

è molto inefficiente perché MySQL vengono elaborati tutti i record della tabella eseguendo una tabella completa scansione su tutte le righe, ordina in modo casuale.

+1

La tabella potrebbe avere ID mancanti da qualche parte nel mezzo, quindi la selezione corretta sarebbe alla fine: 'SELECT * da tablle WHERE id> = @row LIMIT 1;' – cephuo

0

calcolare l'ora corrente nel codice PHP e passare alla query. questo si tradurrà in un valore statico che può essere memorizzato nella cache.

nota che potresti anche avere un bug nascosto. visto che stai solo prendendo l'ora, hai solo 24 valori diversi, che si ripetono ogni giorno. il che significa che quello che viene mostrato alle 13 di oggi sarà anche lo stesso di quello che verrà mostrato domani alle 6. potresti voler cambiare la situazione.

+1

l'ora è appena utilizzata come seme per il casuale generatore di numeri. Sì, so che ottengo gli stessi risultati alle 14:00 di ogni giorno, ma va bene (a meno che l'elenco di prodotti non cambi in alcun modo) –

0

Non lottare con il cache-- esaltarlo!

Scrivi la tua richiesta come sei (o anche più semplice). Quindi, nel codice, memorizza i risultati nella cache, impostando una scadenza della cache per 1 ora.Se stai usando un livello di memorizzazione nella cache, come memcached, sei impostato. In caso contrario, si può costruire una abbastanza semplice:

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

Se hai bisogno di un nuovo set di dati casuali una volta all'ora, non colpire il database - salva i risultati sul livello di memorizzazione nella cache dell'applicazione (o, se non ce l'ha, inseriscilo in un file temporanei di qualche tipo). La cache delle query è a portata di mano, ma se non hai mai bisogno di eseguire una query, ancora meglio ...

1

Questa sarà una query notevolmente sgradevole se è necessario ordinare un set di dati di grandi dimensioni in un ordine casuale (che in realtà richiede un ordinamento), quindi elimina tutti tranne i primi 40 record.

Una soluzione migliore sarebbe quella di selezionare solo 40 record casuali. Ci sono molti modi per farlo e di solito dipende dall'avere chiavi distribuite in modo uniforme.

Un'altra opzione consiste nel selezionare i 40 record casuali in un processo batch che viene eseguito una sola volta all'ora (o qualsiasi altra cosa) e quindi ricorda quali sono.