2009-08-20 24 views
6

Mam tabelę w bazie danych MySQL, z której chcę wybrać wiersz z najbliżej datownika do innego danego znacznika czasu.Najbardziej skuteczny sposób na znalezienie najbliższej liczby całkowitej w MySQL?

time to kolumna znacznika czasu (całkowity znacznik czasu UNIX). Wybrałem 1250710000 arbitralnie.

To jest kwerenda, że ​​mam wymyślić, i zastanawiam się, czy jest bardziej efektywny sposób to zrobić:

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

Jest to najlepszy sposób to zrobić?

Odpowiedz

10

Zakładając time jest indeksowana, można uzyskać następny rekord prawie za darmo:

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

A jeśli się nie mylę, to samo powinno dotyczyć poprzedniego rekordu, MySQL będzie po prostu przeczytać indeksuj w odwrotnej kolejności. Użyj UNION z dwóch, uporządkuj je według daty i czasu! Wynik będzie wyglądać następująco

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 

najlepiej, zamiast > i < należy użyć >= i <= i uwzględniają rekord odniesienia przy użyciu swojego podstawowego identyfikatora, w celu uwzględnienia zapisów dzielących ten sam znacznik czasu.

+0

Cholera! Właśnie pisałem prawie to! – NickZoic

+0

Świetny pomysł, ale referencyjny znacznik czasu ("1250710000" w tym przypadku) nie znajduje się w tej samej tabeli. Powiedziawszy to, zakładam, że to zapytanie jest mniej więcej takie same pod względem wydajności? – heyitsme

+0

** @ cyouung: ** To zapytanie nie jest takie samo pod względem wydajności. Twoje zapytanie składa się z 'ABS (time - 125071000)' on * każdego wiersza *. Dopóki masz indeks "time", to zapytanie nigdy nie będzie czytać więcej niż dwa wiersze. –

1

Jak powiedział Evan, sposób w jaki go masz jest w porządku. Poleciłbym indeks na tym polu sygnatury czasowej, aby MySQL mógł skanować mniejszy indeks, a nie całą tabelę. Również chciałbym spróbować „boks”, aby zobaczyć, czy indeks może przyspieszyć:

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

Powyższe limity zapytań do około +/- 1 dzień. Będziesz musiał wykonać pewne testy porównawcze, aby sprawdzić, czy dodatkowe skanowanie indeksu (klauzula where) jest szybsze niż obliczanie ABS() we wszystkich pozycjach w tabeli.

+0

Nie lubię mieć takie arbitralne ograniczenia. –

1

Czy bardziej efektywny byłby wybór minimalnego czasu, który jest większy, a maksymalny czas jest mniejszy niż po prostu abs. Powinno to zapobiec konieczności operowania na całej tablicy .

SELECT MAX (czas) AS prev GDZIE czas < 1250710000;

WYBIERZ MIN (czas) AS następny GDZIE czas> 1250710000;

WYBIERZ MIN (ABS (poprzedni), ABS (następny));

Mój SQL nie jest wystarczająco silny, aby połączyć je w jeden, a narzut trzech zapytań może zabić jakiekolwiek oszczędności, ale może być to możliwe.

Powiązane problemy