sql >> Base de Datos >  >> RDS >> PostgreSQL

La poda de partición basada en la restricción de verificación no funciona como se esperaba

Su columna created_at es timestamp without time zone .

Pero now() devuelve timestamp with time zone . La expresión now() - '1 hour'::interval está siendo obligado a timestamp [without time zone] , que conlleva dos problemas :

1.) No pediste este, pero la expresión no es confiable. Su resultado depende de la configuración de la zona horaria actual de la sesión en la que se está ejecutando la consulta. Detalles aquí:

Para aclarar la expresión, podría usar:

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

O simplemente (lea el manual aquí) :

LOCALTIMESTAMP  -- explicitly take the local time

Consideraría trabajar con timestamptz en cambio.
Ninguno resuelve su segundo problema:

2.) Respuesta a su pregunta. La exclusión de restricciones no funciona. Por documentación:

Énfasis en negrita mío.

now() es la implementación de Postgres de CURRENT_TIMESTAMP . Como puede ver en el catálogo del sistema, solo es STABLE , no IMMUTABLE :

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

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

Soluciones

1.) Puede superar la limitación proporcionando una constante en WHERE condición (que siempre es "inmutable"):

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

2.) O "falsificando" una función inmutable:

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

Y luego:

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

Sin embargo, tenga cuidado de cómo usa esto:while now() es STABLE (no cambia durante la duración de una transacción), si cambie entre transacciones, así que tenga cuidado de no usar esto en declaraciones preparadas (excepto como valor de parámetro) o índices o cualquier cosa que pueda morderlo.

3.) O puede agregar una constante aparentemente redundante WHERE cláusulas a su consulta actual que coincidan con la restricción en su partición:

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;

Solo asegúrate de que now() - '1 hour'::interval cae en la partición correcta o no obtiene resultados, obviamente.

Aparte:preferiría usar esta expresión en CHECK restricciones y consulta. Más fácil de manejar y hace lo mismo:

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