Si realmente tiene una columna de tipo timestamp
e interpretarlo (en partes) dependiendo de la zona horaria actual, y esta zona horaria puede variar, entonces un índice es generalmente imposible . Solo puede crear un índice en IMMUTABLE
datos...
Después de la actualización:
Para responder a estas preguntas:
- ¿Qué reservas comienzan "hoy"?
- ¿Qué reservas tienen fechas de inicio en el futuro?
- ¿Qué reservas tienen fechas de inicio en el pasado?
... es mejor que almacene un timestamp with time zone
. Solo una date
no es lo suficientemente preciso.
Siempre y cuando solo estemos interesados en el "hoy" local (como se define en la zona horaria actual ), no necesita guardar la zona horaria explícitamente. No nos importa en qué lugar del mundo suceda, solo necesitamos un tiempo absoluto para comparar.
Luego, para obtener reservas a partir de "hoy", simplemente:
SELECT *
FROM reservations
WHERE start_on::date = current_date;
Pero esto no sargable
porque start_on::date
es una expresión derivada y tampoco podemos construir un índice funcional para esto (sin trucos sucios) porque la expresión depende de la zona horaria actual y no es IMMUTABLE
.
En su lugar , compare con el inicio y el final de "nuestro" día en horario UTC:
SELECT *
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz; -- exclude upper border
Ahora, este índice simple puede admitir la consulta:
CREATE INDEX ON reservations (start_on);
Demostración
SQL Fiddle no funciona en el cajero automático. Aquí hay una pequeña demostración para ayudar a entender:
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;
Más explicaciones y enlaces aquí:
Ignorar las zonas horarias por completo en Rails y PostgreSQL