Jeśli masz indeks z created
jako wiodąca kolumna MySQL może być w stanie wykonać skanowanie wsteczne. Jeśli masz okres 24 godzin, w którym nie ma żadnych wydarzeń, możesz zwracać wiersz, który NIE pochodzi z tego okresu. Aby upewnić się, że otrzymujesz wiersz w tym okresie, naprawdę musisz uwzględnić dolną granicę dla created
również kolumnę, coś takiego:
SELECT * FROM `eventos`
WHERE ...
AND `created` < FROM_UNIXTIME( {$timestamp} )
AND `created` >= DATE_ADD(FROM_UNIXTIME( {$timestamp} ),INTERVAL -24 HOUR)
ORDER BY `created` DESC
LIMIT 1
Myślę, że kluczem do wydajności jest tutaj indeks z created
jako kolumnę wiodącą, wraz ze wszystkimi (lub większością) innych kolumn, do których odwołuje się klauzula WHERE, i upewniając się, że indeks jest używany przez zapytanie.
Jeśli potrzebujesz innego przedziału czasu, z dokładnością do sekundy, to podejście można łatwo uogólnić.
SELECT * FROM `eventos`
WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL 0*{$nsecs} SECOND)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*{$nsecs} SECOND)
ORDER BY `created` DESC
LIMIT 1
Z twojego kodu wygląda na to, że okresy 24-godzinne są ograniczone w dowolnym czasie... jeśli funkcja czasu zwraca np. 1341580800 („2012-07-06 13:20”), wtedy wszystkie twoje dziesięć okresów będzie trwało od 13:20 danego dnia do 13:20 następnego dnia.
(UWAGA:upewnij się, że jeśli twój parametr jest uniksową liczbą całkowitą ze znacznikiem czasu, to jest to poprawnie interpretowane przez bazę danych.)
Bardziej wydajne może być pobranie dziesięciu wierszy w jednym zapytaniu. Jeśli istnieje gwarancja, że „sygnatura czasowa” jest unikatowa, można stworzyć takie zapytanie, ale tekst zapytania będzie znacznie bardziej złożony niż ten, który masz teraz. Moglibyśmy namieszać z uzyskaniem MAX(timestamp_) w każdym okresie, a następnie dołączeniem do tego z powrotem, aby uzyskać wiersz… ale to będzie naprawdę nieporządne.
Gdybym miał spróbować wyciągnąć wszystkie dziesięć wierszy, prawdopodobnie spróbowałbym użyć UNION ALL
podejście, niezbyt ładne, ale przynajmniej można je dostroić.
SELECT p0.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL 0*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p0
UNION ALL
SELECT p1.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p1
UNION ALL
SELECT p2.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -3*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p2
UNION ALL
SELECT p3.*
FROM ...
Znowu można to uogólnić, aby przekazać jako argument w ciągu kilku sekund. Zamień GODZINĘ na SECOND i zastąp „24” parametrem wiązania, który ma liczbę sekund.
Jest dość długi, ale powinien działać poprawnie.
Innym naprawdę niechlujnym i skomplikowanym sposobem odzyskania tego w jednym zestawie wyników byłoby użycie widoku wbudowanego w celu uzyskania znacznika czasu zakończenia dla dziesięciu okresów, coś takiego:
SELECT p.period_end
FROM (SELECT DATE_ADD(t.t_,INTERVAL -1 * i.i_* {$nsecs} SECOND) AS period_end
FROM (SELECT FROM_UNIXTIME( {$timestamp} ) AS t_) t
JOIN (SELECT 0 AS i_
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
) i
) p
A potem dołącz do swojego stołu...
ON `created` < p.period_end
AND `created` >= DATE_ADD(p.period_end,INTERVAL -1 * {$nsecs} SECOND)
I wycofaj MAX(utworzone) dla każdego okresu GROUP BY p.period_end, zapakuj to w widok wbudowany.
A następnie dołącz go z powrotem do swojego stołu, aby uzyskać każdy wiersz.
Ale to jest naprawdę, bardzo niechlujne, trudne do zrozumienia i prawdopodobnie nie będzie szybsze (lub bardziej wydajne) niż to, co już robisz. Największą poprawą, jaką możesz wprowadzić, jest czas potrzebny na uruchomienie 9 zapytań.