sql >> Database teknologi >  >> RDS >> PostgreSQL

Optimer/indekser tidszoneforespørgsel

Hvis du faktisk har en kolonne af typen timestamp og fortolke det (i dele) afhængigt af den aktuelle tidszone, og denne tidszone kan variere, så er et indeks generelt umuligt . Du kan kun bygge et indeks på IMMUTABLE data ...

Efter opdatering:

For at besvare disse spørgsmål:

  1. Hvilke reservationer starter "i dag"?
  2. Hvilke reservationer har startdatoer i fremtiden?
  3. Hvilke reservationer har tidligere startdatoer?

... du bedst gemmer et timestamp with time zone . Bare en date er ikke præcis nok.

Så længe vi kun er interesserede i det lokale "i dag" (som defineret af den aktuelle tidszone ), gør vi ikke skal gemme tidszonen eksplicit. Vi er ligeglade med, hvor i verden det sker, vi har kun brug for et absolut tidspunkt at sammenligne med.

Så for at få reservationer fra "i dag" skal du blot:

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

Men dette er ikke sargerbart fordi start_on::date er et afledt udtryk, og vi kan heller ikke bygge et funktionelt indeks for dette (uden beskidte tricks), fordi udtrykket afhænger af den aktuelle tidszone og ikke er IMMUTABLE .

I stedet , sammenlign med starten og slutningen af ​​"vores" dag i UTC-tid:

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

Nu kan dette simple indeks understøtte forespørgslen:

CREATE INDEX ON reservations (start_on);

Demo

SQL Fiddle er nede i ATM. Her er en lille demo for at hjælpe med at forstå:

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;

Mere forklaring og links her:
Ignorerer tidszoner helt i Rails og PostgreSQL



  1. Valg af poster mellem to datoer

  2. konverter mysql-resultat til json med korrekte typer

  3. PHP MySQLi multi_query forberedt erklæring

  4. Angiv standardskema for JDBC-puljen i weblogic/oracle