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

L'eliminazione delle partizioni in base al vincolo di controllo non funziona come previsto

La tua colonna created_at è timestamp without time zone .

Ma now() restituisce timestamp with time zone . L'espressione now() - '1 hour'::interval viene costretto a timestamp [without time zone] , che comporta due problemi :

1.) Non hai chiesto questo, ma l'espressione è inaffidabile. Il risultato dipende dall'impostazione del fuso orario corrente della sessione in cui viene eseguita la query. Dettagli qui:

Per rendere chiara l'espressione, potresti usare:

now() AT TIME ZONE 'Europe/London' -- your time zone here

O semplicemente (leggi il manuale qui) :

LOCALTIMESTAMP  -- explicitly take the local time

Prenderei in considerazione l'idea di lavorare con timestamptz invece.
Nessuno risolve il tuo secondo problema:

2.) Rispondi alla tua domanda. L'esclusione dei vincoli non funziona. Per documentazione:

Enfasi in grassetto la mia.

now() è l'implementazione Postgres di CURRENT_TIMESTAMP . Come puoi vedere nel catalogo del sistema, è solo STABLE , non IMMUTABLE :

SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';

proname | provolatile
--------+------------
now     | s              -- meaning: STABLE

Soluzioni

1.) Puoi superare la limitazione fornendo una costante in WHERE condizione (che è sempre "immutabile"):

select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp;  -- derived from your example

2.) O "fingendo" una funzione immutabile:

CREATE FUNCTION f_now_immutable()
  RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC'  -- your time zone here
$func$  LANGUAGE sql IMMUTABLE;

E poi:

select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'

Fai attenzione a come lo usi:while now() è STABLE (non cambia per la durata di una transazione), fa cambiare tra le transazioni, quindi fai attenzione a non usarlo in dichiarazioni preparate (tranne come valore di parametro) o indici o qualsiasi cosa in cui potrebbe morderti.

3.) Oppure puoi aggiungere una costante apparentemente ridondante WHERE clausole alla query corrente che corrispondono al vincolo sulla partizione:

SELECT count(*)
FROM   events
WHERE  created_at > now() - '1 hour'::interval
AND    created_at >= '2015-04-01 00:00:00'::timestamp
AND    created_at <= '2015-04-30 23:59:59.999999'::timestamp;

Assicurati solo che now() - '1 hour'::interval cade nella partizione giusta o non ottieni risultati, ovviamente.

A parte:preferirei usare questa espressione in CHECK vincoli e interrogazione. Più facile da maneggiare e fa lo stesso:

       created_at >= '2015-04-01 0:0'::timestamp
AND    created_at <  '2015-05-01 0:0'::timestamp