sql >> Databáze >  >> RDS >> PostgreSQL

Odečtěte hodiny od funkce now().

Odpověď na timestamp

Musíte pochopit povahu datových typů timestamp (timestamp without time zone ) a timestamptz (timestamp with time zone ). Pokud ne, přečtěte si nejprve toto:

  • Úplné ignorování časových pásem v Rails a PostgreSQL

AT TIME ZONE konstrukt transformuje timestamp na timestamptz , což je téměř jistě špatný krok pro váš případ:

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

První , zabíjí výkon. Použití AT TIME ZONE do sloupce eventtime způsobí, že výraz není sargable . Postgres nemůže používat prosté indexy v eventtime . Ale i bez indexu jsou sargable výrazy levnější. Upravte hodnoty filtru namísto manipulace s každou hodnotou řádku.
To můžete kompenzovat pomocí indexu shodného výrazu, ale pravděpodobně je to jen nedorozumění a špatné.

Co se stane v tomto výrazu?

  1. AT TIME ZONE 'CET' transformuje timestamp hodnota eventtime na timestamptz připojením časového posunu vašeho aktuálního časového pásma. Při použití časového pásma name (nikoli číselný posun nebo zkratka), zohledňuje to také pravidla DST (letního času), takže pro „zimní“ časová razítka získáte jiný posun. V podstatě dostanete odpověď na otázku:

    Jaké je odpovídající časové razítko UTC pro dané časové razítko v daném časovém pásmu?

    Při zobrazení výsledek pro uživatele je naformátován jako místní časové razítko s příslušným časovým posunem pro aktuální časové pásmo relace. (Může nebo nemusí být stejný jako výraz použitý ve výrazu).

  2. Řetězcové literály na pravé straně nemají žádný datový typ, takže typ je odvozen z přiřazení ve výrazu. Protože to je timestamptz nyní jsou oba přetypovány na timestamptz , za předpokladu aktuálního časového pásma relace.

    Jaké je odpovídající časové razítko UTC pro dané časové razítko pro nastavení časového pásma aktuální relace.

    Posun se může lišit podle pravidel DST.

Krátký dlouhý příběh , pokud vždy pracovat se stejným časovým pásmem:CET nebo 'Europe/Berlin' - Totéž pro současná časová razítka, ale ne pro historická nebo (možná) budoucí, můžete si to prostě uříznout.

Druhý problém s výrazem:BETWEEN je téměř vždy špatně s timestamp hodnoty. Viz:

  • Optimalizace výpisu data BETWEEN
  • Najděte překrývající se období v 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() je Postgres implementace standardu SQL CURRENT_TIMESTAMP . Oba vrátí timestamptz (nikoli timestamp !). Můžete použít buď.
now()::date je ekvivalentní CURRENT_DATE . Obojí závisí na aktuálním nastavení časového pásma.

Měli byste mít index formuláře:

CREATE INDEX foo ON t_el_eventlog(sourceid, eventtime)

Nebo chcete-li povolit skenování pouze na základě indexu:

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

Pokud působíte v různých časových pásmech, věci se zkomplikují a měli byste použít timestamptz za všechno.

Alternativa pro timestamptz

Před aktualizací otázky se zdálo, že na časových pásmech záleží. Když řešíte různá časová pásma, "dnes" je funkční závislost aktuálního časového pásma. Lidé na to mají tendenci zapomínat.

Chcete-li pracovat pouze s aktuálním nastavením časového pásma relace, použijte stejný dotaz jako výše. Při spuštění v jiném časovém pásmu jsou výsledky ve skutečnosti nesprávné. (Platí také pro výše uvedené.)

Chcete-li zaručit správný výsledek pro dané časové pásmo (ve vašem případě „Evropa/Berlín“) bez ohledu na aktuální nastavení časového pásma relace, použijte místo toho tento výraz:

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

Uvědomte si, že AT TIME ZONE konstrukt vrací timestamp pro timestamptz vstup a naopak.

Jak bylo zmíněno na začátku, všechny krvavé detaily zde:

  • Úplné ignorování časových pásem v Rails a PostgreSQL


  1. Neo4j - Odstranit vztah pomocí Cypher

  2. SQL, jak aktualizovat strukturu tabulky

  3. Vytvořte databázi SQL Server pomocí SQLOPS

  4. jQuery Ověřte použití vzdálené metody pro kontrolu, zda uživatelské jméno již existuje