PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Zeitzonenabfrage optimieren/indizieren

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:

  1. Welche Reservierungen beginnen "heute"?
  2. Welche Reservierungen haben Startdaten in der Zukunft?
  3. 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