PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Optymalizacja/indeksowanie zapytania o strefę czasową

Jeśli faktycznie masz kolumnę typu timestamp i zinterpretuj go (częściowo) w zależności od aktualnej strefy czasowej, a ta strefa czasowa może się różnić, wtedy indeks jest generalnie niemożliwy . Indeks można zbudować tylko na IMMUTABLE dane ...

Po aktualizacji:

Aby odpowiedzieć na te pytania:

  1. Jakie rezerwacje zaczynają się „dzisiaj”?
  2. Jakie rezerwacje mają daty rozpoczęcia w przyszłości?
  3. Jakie rezerwacje mają daty rozpoczęcia w przeszłości?

... najlepiej przechowywać timestamp with time zone . Tylko date nie jest wystarczająco precyzyjny.

O ile interesuje nas tylko lokalne „dzisiaj” (zdefiniowane przez obecną strefę czasową ), nie trzeba wyraźnie zapisać strefę czasową. Nie obchodzi nas, gdzie na świecie to się dzieje, potrzebujemy tylko absolutnego czasu do porównania.

Następnie, aby uzyskać rezerwacje zaczynające się „dzisiaj”, po prostu:

SELECT *
FROM   reservations
WHERE  start_on::date = current_date;

Ale to jest nie sargable ponieważ start_on::date jest wyrażeniem pochodnym i nie możemy również zbudować dla niego indeksu funkcjonalnego (bez brudnych sztuczek), ponieważ wyrażenie zależy od bieżącej strefy czasowej i nie jest IMMUTABLE .

Zamiast tego , porównaj z początkiem i końcem „naszego” dnia w czasie UTC:

SELECT *
FROM   reservations
WHERE  start_on >= current_date::timestamptz
AND    start_on < (current_date + 1)::timestamptz; -- exclude upper border

Teraz ten prosty indeks może obsługiwać zapytanie:

CREATE INDEX ON reservations (start_on);

Demo

SQL Fiddle nie działa ATM. Oto mała demonstracja, która pomoże zrozumieć:

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;

Więcej wyjaśnień i linków tutaj:
Ignorowanie stref czasowych w Railsach i PostgreSQL



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Przypisz ten sam identyfikator do wierszy z tą samą kombinacją danych

  2. Uwagi dotyczące indeksów PostgreSQL B-Tree

  3. Przekazywanie identyfikatora użytkownika do wyzwalaczy PostgreSQL

  4. HikariCP z PostgreSQL:setQueryTimeout(int) nie jest jeszcze zaimplementowany

  5. Błąd:Klucz ... nie występuje w tabeli