PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Optimiser/Indexer la requête de fuseau horaire

Si vous avez réellement une colonne de type timestamp et l'interpréter (en partie) en fonction du fuseau horaire actuel, et ce fuseau horaire peut varier, alors un index est généralement impossible . Vous ne pouvez construire un index que sur IMMUTABLE données ...

Après la mise à jour :

Pour répondre à ces questions :

  1. Quelles réservations commencent "aujourd'hui" ?
  2. Quelles réservations ont des dates de début dans le futur ?
  3. Quelles réservations ont des dates de début dans le passé ?

... il vaut mieux stocker un timestamp with time zone . Juste une date n'est pas assez précis.

Tant que nous ne nous intéressons qu'au "aujourd'hui" local (tel que défini par le fuseau horaire actuel ), nous ne le faisons pas besoin d'enregistrer explicitement le fuseau horaire. Peu importe où cela se passe dans le monde, nous n'avons besoin que d'un temps absolu pour comparer.

Ensuite, pour obtenir des réservations commençant "aujourd'hui", il vous suffit de :

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

Mais ce n'est pas sargable car start_on::date est une expression dérivée et nous ne pouvons pas non plus construire un index fonctionnel pour cela (sans astuce) car l'expression dépend du fuseau horaire actuel et n'est pas IMMUTABLE .

Au lieu de cela , comparer au début et à la fin de "notre" journée en heure UTC :

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

Désormais, cet index simple peut prendre en charge la requête :

CREATE INDEX ON reservations (start_on);

Démo

SQL Fiddle est en panne ATM. Voici une petite démo pour aider à comprendre :

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;

Plus d'explications et de liens ici :
Ignorer complètement les fuseaux horaires dans Rails et PostgreSQL