PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Otimizar/Indexar consulta de fuso horário


Se você realmente tiver uma coluna do tipo timestamp e interpretá-lo (em partes) dependendo do fuso horário atual, e esse fuso horário pode variar, então um índice geralmente é impossível . Você só pode construir um índice em IMMUTABLE dados ...

Após a atualização:


Para responder a estas perguntas:
  1. Quais reservas começam "hoje"?
  2. Quais reservas têm datas de início no futuro?
  3. Quais reservas têm datas de início no passado?

... é melhor armazenar um timestamp with time zone . Apenas uma date não é suficientemente preciso.

Contanto que estejamos interessados ​​apenas no "hoje" local (conforme definido pelo fuso horário atual ), nós não precisa salvar o fuso horário explicitamente. Não nos importamos em que lugar do mundo isso aconteça, só precisamos de um tempo absoluto para comparar.

Então, para obter reservas a partir de "hoje" basta:
SELECT *
FROM   reservations
WHERE  start_on::date = current_date;

Mas isso é não sargable porque start_on::date é uma expressão derivada e também não podemos construir um índice funcional para isso (sem truques sujos) porque a expressão depende do fuso horário atual e não é IMMUTABLE .

Em vez disso , compare com o início e o fim de "nosso" dia no horário UTC:
SELECT *
FROM   reservations
WHERE  start_on >= current_date::timestamptz
AND    start_on < (current_date + 1)::timestamptz; -- exclude upper border

Agora, este índice simples pode suportar a consulta:
CREATE INDEX ON reservations (start_on);

Demonstração


SQL Fiddle está inativo ATM. Aqui está uma pequena demonstração para ajudar 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;

Mais explicações e links aqui:
Ignorando completamente os fusos horários em Rails e PostgreSQL