PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Ottimizza/indicizza la query sul fuso orario

Se hai effettivamente una colonna di tipo timestamp e interpretarlo (in parti) a seconda del fuso orario corrente, e questo fuso orario può variare, quindi un indice è generalmente impossibile . Puoi creare un indice solo su IMMUTABLE dati...

Dopo l'aggiornamento:

Per rispondere a queste domande:

  1. Quali prenotazioni iniziano "oggi"?
  2. Quali prenotazioni hanno date di inizio future?
  3. Quali prenotazioni hanno date di inizio nel passato?

... è meglio memorizzare un timestamp with time zone . Solo una date non è abbastanza preciso.

Finché siamo interessati solo all'"oggi" locale (come definito dal fuso orario attuale ), noi non necessario salvare il fuso orario in modo esplicito. Non ci interessa in quale parte del mondo accada, abbiamo solo bisogno di un tempo assoluto per confrontarci.

Quindi, per ottenere prenotazioni a partire da "oggi" è sufficiente:

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

Ma questo è non sargable perché start_on::date è un'espressione derivata e non possiamo nemmeno creare un indice funzionale per questo (senza trucchi sporchi) perché l'espressione dipende dal fuso orario corrente e non è IMMUTABLE .

Invece , confronta con l'inizio e la fine del "nostro" giorno nell'ora UTC:

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

Ora, questo semplice indice può supportare la query:

CREATE INDEX ON reservations (start_on);

Dimostrazione

SQL Fiddle è inattivo ATM. Ecco una piccola demo per aiutare a capire:

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;

Ulteriori spiegazioni e collegamenti qui:
Ignora del tutto i fusi orari in Rails e PostgreSQL