Wenn Sie tatsächlich eine Spalte vom Typ timestamp
haben und (in Teilen) abhängig von der aktuellen Zeitzone interpretieren, und diese Zeitzone variieren kann, dann ist ein Index generell unmöglich . Sie können einen Index nur auf IMMUTABLE
aufbauen Daten ...
Nach dem Update:
So beantworten Sie diese Fragen:
- Welche Reservierungen beginnen "heute"?
- Welche Reservierungen haben Startdaten in der Zukunft?
- Welche Reservierungen haben Startdaten in der Vergangenheit?
... hinterlegen Sie am besten einen timestamp with time zone
. Nur ein date
ist nicht präzise genug.
Solange uns nur das lokale „Heute“ (definiert durch die aktuelle Zeitzone) interessiert ), tun wir nicht müssen die Zeitzone explizit speichern. Uns ist egal, wo auf der Welt es passiert, wir brauchen nur eine absolute Zeit zum Vergleichen.
Dann, um Reservierungen ab "heute" zu erhalten, einfach:
SELECT *
FROM reservations
WHERE start_on::date = current_date;
Aber das ist nicht sargable
weil start_on::date
ist ein abgeleiteter Ausdruck und wir können dafür (ohne schmutzige Tricks) auch keinen funktionalen Index bauen, weil der Ausdruck von der aktuellen Zeitzone abhängt und nicht IMMUTABLE
ist .
Stattdessen , vergleichen Sie mit Beginn und Ende „unseres“ Tages in UTC-Zeit:
SELECT *
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz; -- exclude upper border
Nun kann dieser einfache Index die Abfrage unterstützen:
CREATE INDEX ON reservations (start_on);
Demo
SQL Fiddle ist ausgefallen. ATM. Hier ist eine kleine Demo zum besseren Verständnis:
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;
Weitere Erklärungen und Links hier:
Zeitzonen in Rails und PostgreSQL komplett ignorieren