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 :
- Quelles réservations commencent "aujourd'hui" ?
- Quelles réservations ont des dates de début dans le futur ?
- 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