sql >> Base de Datos >  >> RDS >> PostgreSQL

Optimizar/indexar consulta de zona horaria

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:

  1. ¿Qué reservas comienzan "hoy"?
  2. ¿Qué reservas tienen fechas de inicio en el futuro?
  3. ¿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