MySQL WYBIERZ GDZIE data i godzina pasuje do dnia (i niekoniecznie do godziny)

127

Mam tabelę zawierającą kolumnę z datą i godziną. Chcę zwrócić wszystkie rekordy z danego dnia niezależnie od godziny. Innymi słowy, jeśli moja tabela zawiera tylko następujące 4 rekordy, to tylko 2 i 3 zostaną zwrócone, jeśli ograniczę się do 2012-12-25.

2012-12-24 00:00:00
2012-12-25 00:00:00
2012-12-25 06:00:00
2012-12-26 05:00:00
user1032531
źródło
Zobacz odpowiedź Johna Woo na stackoverflow.com/questions/14769026/ ...
ekerner

Odpowiedzi:

326

NIGDY NIGDY nie używaj takiego selektora DATE(datecolumns) = '2012-12-24'- to zabójca wydajności:

  • obliczy DATE()dla wszystkich wierszy, w tym tych, które nie pasują
  • uniemożliwi to użycie indeksu dla zapytania

Jest znacznie szybszy w użyciu

SELECT * FROM tablename 
WHERE columname BETWEEN '2012-12-25 00:00:00' AND '2012-12-25 23:59:59'

ponieważ pozwoli to na użycie indeksu bez obliczeń.

EDYTOWAĆ

Jak wskazał Used_By_Already, w czasie od pierwszej odpowiedzi w 2012 r. Pojawiły się wersje MySQL, w których używanie „23: 59: 59” jako końca dnia nie jest już bezpieczne. Zaktualizowana wersja powinna przeczytać

SELECT * FROM tablename 
WHERE columname >='2012-12-25 00:00:00'
AND columname <'2012-12-26 00:00:00'

Istota odpowiedzi, tj. Unikanie selektora na wyliczonym wyrażeniu, oczywiście pozostaje aktualna.

Eugen Rieck
źródło
Już miałem skomentować, że rozwiązanie a1ex07 nie wydaje się tak dobre, jak inne. Po przeczytaniu twojego posta może muszę zmienić moje myślenie!
user1032531
2
Właśnie przetestowane na dwóch serwerach, powyższe jest DUŻO (co najmniej 10x) szybsze niż date () = '', szczególnie w przypadku dużych tabel. Dzięki
zzapper
1
@KonradViltersten Użyłem bardzo rozwlekłego sposobu sformułowania zapytania, aby było bardziej czytelne i skierować do sedna mój punkt widzenia, a nie uściślając go. Odpowiedź a1ex07 ma rzadką składnię.
Eugen Rieck
9
@KonradViltersten - jeszcze lepiej: WHERE col >= '2012-12-25' AND col < '2012-12-25' + INTERVAL 1 DAY. Unika 0 czas i działa na DATE, DATETIME, DATETIME(6), itd. I zajmuje się LEAP dzień itp
Rick James
1
'2012-12-25 23:59:59' NIE JEST WAŻNY jako koniec dnia, zawsze był to zły pomysł i będzie powodować błędy w wersjach MySQL obsługujących precyzję poniżej sekundy. O wiele lepiej jest zastosować podejście Ricka Jamesa (powyżej) lub a1ex07 (inna odpowiedź)
Used_By_Already
34

... WHERE date_column >='2012-12-25' AND date_column <'2012-12-26'może potencjalnie działać lepiej (jeśli masz indeks na kolumnie_data) niż DATE.

a1ex07
źródło
1
Właściwie to zastanawiam się, co jest szybsze - to czy BETWEENrozwiązanie ... ktoś bechmarked?
jave.web
6
Nie powinno być żadnej różnicy. BETWEENto tylko sposób na pisanie field >= value1 and fied<= value2.
a1ex07
1
Zwróć uwagę, że zgodnie z podręcznikiem MySQL: „Aby uzyskać najlepsze wyniki podczas używania BETWEEN z wartościami daty lub godziny, użyj funkcji CAST (), aby jawnie przekonwertować wartości na żądany typ danych. Przykłady: Jeśli porównujesz DATETIME z dwiema wartościami DATE, przekonwertuj DATE wartości na wartości DATETIME. Jeśli używasz stałej łańcuchowej, takiej jak „2001-1-1” w porównaniu z DATE, rzutuj ciąg na DATE. " Więc jeśli nie są tego samego typu, najlepiej je jawnie rzutować.
techdude
21

Możesz użyć %:

SELECT * FROM datetable WHERE datecol LIKE '2012-12-25%'
Ghilas BELHADJ
źródło
13
LIKE wydaje się być tak powolne jak DATE (datetimecol). Lepiej użyj rozwiązania Eugena lub a1ex07.
Marie Fischer
3
Nie zawsze chodzi o prędkość. Więc podoba mi się to rozwiązanie. Jest dużo bardziej czytelny.
Simon Hansen