PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

A remoção de partição com base na restrição de verificação não está funcionando conforme o esperado


Sua coluna created_at é timestamp without time zone .

Mas now() retorna timestamp with time zone . A expressão now() - '1 hour'::interval está sendo forçado a timestamp [without time zone] , que traz dois problemas :

1.) Você não pediu este, mas a expressão não é confiável. Seu resultado depende da configuração de fuso horário atual da sessão em que a consulta está sendo executada. Detalhes aqui:

Para tornar a expressão clara, você pode usar:
now() AT TIME ZONE 'Europe/London' -- your time zone here

Ou apenas (leia o manual aqui) :
LOCALTIMESTAMP  -- explicitly take the local time

Eu consideraria trabalhar com timestamptz em vez disso.
Nenhum dos dois resolve seu segundo problema:

2.) Responda à sua pergunta. A exclusão de restrição não funciona. Por documentação:

Minha ênfase em negrito.

now() é a implementação Postgres de CURRENT_TIMESTAMP . Como você pode ver no catálogo do sistema, é apenas STABLE , não IMMUTABLE :
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';

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

Soluções


1.) Você pode superar a limitação fornecendo uma constante no WHERE condição (que é sempre "imutável"):
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp;  -- derived from your example

2.) Ou "fingindo" uma função imutável:
CREATE FUNCTION f_now_immutable()
  RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC'  -- your time zone here
$func$  LANGUAGE sql IMMUTABLE;

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

Tenha cuidado como você usa isso:while now() é STABLE (não muda durante a transação), muda altere entre as transações, portanto, tome cuidado para não usar isso em instruções preparadas (exceto como valor de parâmetro) ou índices ou qualquer coisa que possa mordê-lo.

3.) Ou você pode adicionar uma constante aparentemente redundante WHERE cláusulas para sua consulta atual que correspondem à restrição em sua partição:
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;

Apenas certifique-se de que now() - '1 hour'::interval cai na partição certa ou você não obtém resultados, obviamente.

A parte:eu prefiro usar essa expressão em CHECK restrições e consultas. Mais fácil de manusear e faz o mesmo:
       created_at >= '2015-04-01 0:0'::timestamp
AND    created_at <  '2015-05-01 0:0'::timestamp