sql >> Databasteknik >  >> RDS >> PostgreSQL

Partitionsbeskärning baserad på kontrollbegränsning fungerar inte som förväntat

Din kolumn created_at är timestamp without time zone .

Men now() returnerar timestamp with time zone . Uttrycket now() - '1 hour'::interval tvingas till timestamp [without time zone] , som har två problem :

1.) Du frågade inte efter den här, men uttrycket är opålitligt. Resultatet beror på den aktuella tidszonsinställningen för sessionen som frågan körs i. Detaljer här:

För att göra uttrycket tydligt kan du använda:

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

Eller bara (läs manualen här) :

LOCALTIMESTAMP  -- explicitly take the local time

Jag skulle överväga att arbeta med timestamptz istället.
Ingen av dem löser ditt andra problem:

2.) Svar på din fråga. Uteslutning av begränsningar fungerar inte. Per dokumentation:

Djärv betoning min.

now() är Postgres-implementeringen av CURRENT_TIMESTAMP . Som du kan se i systemkatalogen är den bara STABLE , inte IMMUTABLE :

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

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

Lösningar

1.) Du kan övervinna begränsningen genom att ange en konstant i WHERE villkor (som alltid är "oföränderligt"):

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

2.) Eller genom att "fejka" en oföränderlig funktion:

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

Och sedan:

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

Var dock försiktig med hur du använder detta:while now() är STABLE (ändras inte under en transaktions varaktighet), gör det det växla mellan transaktioner, så se till att inte använda detta i förberedda uttalanden (förutom som parametervärde) eller index eller något där det kan bita dig.

3.) Eller så kan du lägga till en till synes redundant konstant WHERE satser till din nuvarande fråga som matchar begränsningen på din partition:

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;

Se bara till att now() - '1 hour'::interval faller in i rätt partition eller så får du inga resultat, uppenbarligen.

Bortsett från:Jag skulle hellre använda detta uttryck i CHECK begränsningar och fråga. Lättare att hantera och gör detsamma:

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



  1. Variabeln får NULL efter beräkningar i MySQL Trigger

  2. Komma igång med ProxySQL - MySQL &MariaDB Load Balancing Tutorial

  3. Fråga punkter inom en given radie i MySQL

  4. Oracle konverterar RAW till datumformat