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

Dotaz na optimalizaci/indexování časového pásma

Pokud skutečně máte sloupec typu timestamp a interpretovat jej (po částech) v závislosti na aktuálním časovém pásmu a toto časové pásmo se může lišit, pak je index obecně nemožný . Index můžete vytvořit pouze na IMMUTABLE údaje ...

Po aktualizaci:

Chcete-li odpovědět na tyto otázky:

  1. Jaké rezervace začínají „dnes“?
  2. Jaké rezervace mají datum zahájení v budoucnosti?
  3. Jaké rezervace mají datum zahájení v minulosti?

... nejlépe uložte časové razítko timestamp with time zone . Stačí date není dostatečně přesný.

Dokud nás zajímá pouze místní „dnes“ (definované aktuálním časovým pásmem ), neděláme je třeba explicitně uložit časové pásmo. Je nám jedno, kde na světě se to stane, potřebujeme pouze absolutní čas na srovnání.

Poté, abyste získali rezervace počínaje „dnes“ jednoduše:

SELECT *
FROM   reservations
WHERE  start_on::date = current_date;

Ale toto nelze sargable protože start_on::date je odvozený výraz a ani pro to nemůžeme vytvořit funkční index (bez špinavých triků), protože výraz závisí na aktuálním časovém pásmu a není IMMUTABLE .

Místo toho , porovnejte se začátkem a koncem „našeho“ dne v čase UTC:

SELECT *
FROM   reservations
WHERE  start_on >= current_date::timestamptz
AND    start_on < (current_date + 1)::timestamptz; -- exclude upper border

Nyní tento jednoduchý index může podporovat dotaz:

CREATE INDEX ON reservations (start_on);

Ukázka

SQL Fiddle je mimo provoz bankomatu. Zde je malá ukázka, která vám pomůže pochopit:

CREATE TEMP TABLE reservations (
   reservation_id serial
 , start_on timestamptz NOT NULL
 , time_zone text);    -- we don't need this

INSERT INTO reservations (start_on, time_zone) VALUES
  ('2014-04-09 01:00+02', 'Europe/Vienna')
, ('2014-04-09 23:00+02', 'Europe/Vienna')
, ('2014-04-09 01:00+00', 'UTC')    -- the value is independent of the time zone
, ('2014-04-09 23:00+00', 'UTC')    -- only display depends on current time zone
, ('2014-04-09 01:00-07', 'America/Los_Angeles')
, ('2014-04-09 23:00-07', 'America/Los_Angeles');

SELECT start_on, time_zone 
     , start_on::timestamp             AS local_ts
     , start_on AT TIME ZONE time_zone AS ts_at_tz
     , current_date::timestamptz       AS lower_bound
     , (current_date + 1)::timestamptz AS upper_bound
FROM   reservations
WHERE  start_on >= current_date::timestamptz
AND    start_on < (current_date + 1)::timestamptz;

Další vysvětlení a odkazy zde:
Úplné ignorování časových pásem v Rails a PostgreSQL



  1. Jak provést dotaz SQLite v aplikaci pro Android?

  2. Pomocí SqlDataAdapter vložit řádek

  3. Index generování hibernace a cizí klíč se stejným názvem pro MySQL

  4. Jak nainstalovat a zabezpečit MariaDB na Debian 9