PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Odejmij godziny od funkcji now()

Odpowiedź dla timestamp

Musisz zrozumieć naturę typów danych timestamp (timestamp without time zone ) i timestamptz (timestamp with time zone ). Jeśli nie, przeczytaj najpierw to:

  • Całkowite ignorowanie stref czasowych w Rails i PostgreSQL

AT TIME ZONE konstrukcja przekształca timestamp do timestamp , co prawie na pewno jest niewłaściwym posunięciem w Twoim przypadku:

where eventtime at time zone 'CET' between '2015-06-16 06:00:00'
                                       and '2015-06-17 06:00:00'

Pierwszy , zabija wydajność. Stosuję AT TIME ZONE do kolumny eventtime sprawia, że ​​wyrażenie nie jest sargable . Postgres nie może używać zwykłych indeksów w eventtime . Ale nawet bez indeksu wyrażenia sargable są tańsze. Dostosuj wartości filtrów zamiast manipulować wartościami każdego wiersza.
Możesz mógł zrekompensować pasującym indeksem wyrażenia, ale prawdopodobnie jest to tylko nieporozumienie i i tak źle.

Co się dzieje w tym wyrażeniu?

  1. AT TIME ZONE 'CET' przekształca timestamp wartość eventtime do timestamp dołączając przesunięcie czasowe aktualnej strefy czasowej. W przypadku korzystania ze strefy czasowej nazwa (nie przesunięcie numeryczne lub skrót), uwzględnia to również reguły DST (czas letni), więc otrzymujesz inne przesunięcie dla „zimowych” znaczników czasu. Zasadniczo otrzymujesz odpowiedź na pytanie:

    Jaka jest odpowiednia sygnatura czasowa UTC dla podanej sygnatury czasowej w danej strefie czasowej?

    Podczas wyświetlania wynik dla użytkownika jest sformatowany jako lokalny znacznik czasu z odpowiednim przesunięciem czasu dla bieżącej strefy czasowej sesji. (Może być lub nie być tym samym, co użyte w wyrażeniu).

  2. Literały ciągów po prawej stronie nie mają typu danych, więc typ pochodzi z przypisania w wyrażeniu. Ponieważ to jest timestamptz teraz oba są rzutowane na timestamptz , zakładając aktualną strefę czasową sesji.

    Jaka jest odpowiednia sygnatura czasowa UTC dla podanej sygnatury czasowej dla ustawienia strefy czasowej bieżącej sesji.

    Przesunięcie może się różnić w zależności od reguł czasu letniego.

Krótkie opowiadanie , jeśli zawsze działają w tej samej strefie czasowej:CET lub 'Europe/Berlin' - to samo dla dzisiejszych znaczników czasu, ale nie dla historycznych lub (ewentualnie) przyszłych, możesz po prostu pominąć.

Drugi problem z wyrażeniem:BETWEEN jest prawie zawsze błędny z timestamp wartości. Zobacz:

  • Optymalizuj BETWEEN zestawienie daty
  • Znajdź nakładające się zakresy dat w PostgreSQL
SELECT date_trunc('hour', eventtime) AS hour
     , count(DISTINCT serialnumber)  AS ct  -- sure you need distinct?
FROM   t_el_eventlog
WHERE  eventtime >= now()::date - interval '18 hours'
AND    eventtime <  now()::date + interval '6 hours'
AND    sourceid  =  44  -- don't quote the numeric literal
GROUP  BY 1
ORDER  BY 1;

now() jest implementacją Postgres standardu SQL CURRENT_TIMESTAMP . Oba zwracają timestamptz (nie timestamptz !). Możesz użyć obu.
now()::date jest odpowiednikiem CURRENT_DATE . Oba zależą od aktualnego ustawienia strefy czasowej.

Powinieneś mieć indeks postaci:

CREATE INDEX foo ON t_el_eventlog(sourceid, eventtime)

Lub, aby zezwolić na skanowanie tylko indeksu:

CREATE INDEX foo2 ON t_el_eventlog(sourceid, eventtime, serialnumber)

Jeśli działasz w różnych strefach czasowych, sprawy stają się bardziej skomplikowane i powinieneś użyć timestamptz za wszystko.

Alternatywa dla timestamp

Przed aktualizacją pytania wydawało się, że strefy czasowe mają znaczenie. W przypadku różnych stref czasowych „dzisiaj” jest funkcjonalną zależnością od aktualnej strefy czasowej. Ludzie zwykle o tym zapominają.

Aby po prostu pracować z bieżącym ustawieniem strefy czasowej sesji, użyj tego samego zapytania, co powyżej. W przypadku wykonania w innej strefie czasowej wyniki są w rzeczywistości błędne. (Dotyczy również powyższego.)

Aby zagwarantować poprawny wynik dla danej strefy czasowej (w Twoim przypadku „Europa/Berlin”) niezależnie od bieżącego ustawienia strefy czasowej sesji, użyj tego wyrażenia:

    ((now() AT TIME ZONE 'Europe/Berlin')::date - interval '18 hours')
            AT TIME ZONE 'Europe/Berlin'  -- 2nd time to convert back

Pamiętaj, że AT TIME ZONE konstrukcja zwraca timestamp dla timestamp wejście i odwrotnie.

Jak wspomniano na wstępie, wszystkie krwawe szczegóły tutaj:

  • Całkowite ignorowanie stref czasowych w Rails i PostgreSQL


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak UPDATE i SELECT jednocześnie?

  2. Nie znaleziono odpowiedniego sterownika po dołączeniu potrzebnych sterowników do wtyczki maven-assembly-plugin

  3. Jak zmienić kodowanie kolekcji szablonów bazy danych

  4. Zresetuj licznik automatycznego przyrostu w postgresie

  5. Zamienianie dowolnie wielu wierszy w kolumny w PostgreSQL