2009-08-20 17 views
6

Ho una tabella in un database MySQL da cui voglio selezionare la riga con il timestamp più vicino a un altro data data.Il modo più efficace per trovare il numero intero più vicino in MySQL?

time è la colonna del timestamp (un timestamp UNIX intero). Ho scelto 1250710000 arbitrariamente.

Questa è la domanda che mi è venuta in mente, e mi chiedo se c'è un modo più efficace per farlo:

SELECT *, ABS(time - 1250710000) AS time_dist FROM table 
ORDER BY time_dist ASC LIMIT 1 

È questo il modo migliore per farlo?

risposta

10

Supponendo time è indicizzato, è possibile ottenere il prossimo record di quasi gratuitamente:

SELECT * FROM table WHERE time > 1250710000 ORDER BY time LIMIT 1 

E se non sbaglio, lo stesso dovrebbe valere per il record precedente, MySQL basta leggere il indice in ordine inverso. Usa una UNIONE dei due, ordinali per data diff e voilà! Il risultato sarà simile a questo

SELECT * 
FROM 
(
    (SELECT *, ABS(time - 1250710000) AS time_diff FROM table WHERE time > 1250710000 ORDER BY time ASC LIMIT 1) 
    UNION ALL 
    (SELECT *, ABS(time - 1250710000) AS time_diff FROM table WHERE time < 1250710000 ORDER BY time DESC LIMIT 1) 
) AS tmp 
ORDER BY time_diff 
LIMIT 1 

Idealmente, invece di > e < si dovrebbe usare >= e <= ed escludere il record di riferimento usando il suo id primaria, per tenere conto per i record che condividono la stessa data e ora.

+0

Dannazione! Stavo solo digitando quasi esattamente questo! – NickZoic

+0

Ottima idea, ma il timestamp di riferimento ('1250710000' in questo caso) non si trova nella stessa tabella. Detto questo, presumo che questa query sia la stessa in termini di efficienza? – heyitsme

+0

** @ cyouung: ** Questa query non è la stessa in termini di efficienza. La tua query fa un 'ABS (tempo - 125071000)' su * ogni singola riga *. Finché hai un indice su "ora", questa query non leggerà mai più di due righe. –

1

Come ha detto Evan, il modo in cui ce l'hai va bene. Vorrei raccomandare un indice su quel campo timestamp, in modo che MySQL possa eseguire la scansione dell'indice più piccolo anziché dell'intera tabella. Inoltre, vorrei provare un po 'di boxe' per vedere se l'indice può accelerare le cose:

SELECT *, ABS(time - 1250710000) AS time_dist FROM table 
WHERE time between(1250610000,1250810000) 
ORDER BY time_dist ASC LIMIT 1 

I limiti di cui sopra per interrogare a circa +/- 1 giorno. Dovrai fare alcuni benchmark per vedere se la scansione dell'indice aggiuntiva (la clausola where) è più veloce di calcolare ABS() su tutte le voci nella tabella.

+0

Non mi piace avere limiti arbitrari come quello. –

1

Sarebbe più efficiente selezionare il tempo minimo più grande e il tempo massimo minore rispetto a quelli appena assenti. Questo dovrebbe evitare di dover operare sull'intera tabella .

SELEZIONA MASSIMO (ora) AS precedente DOVE ora < 1250710000;

SELEZIONA MIN (ora) COME successivo DOVE ora> 1250710000;

SELECT MIN (ABS (prev), ABS (successivo));

Il mio SQL non è abbastanza potente da combinare quelli in uno, e il sovraccarico di tre query potrebbe uccidere qualsiasi risparmio, ma potrebbe essere possibile.

Problemi correlati