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:
- Quais reservas começam "hoje"?
- Quais reservas têm datas de início no futuro?
- 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