sql >> データベース >  >> RDS >> PostgreSQL

チェック制約に基づくパーティションプルーニングが期待どおりに機能しない

    あなたの列created_attimestamp without time zoneです 。

    しかし、now() timestamp with time zoneを返します 。式now() - '1 hour'::interval timestamp [without time zone]に強制されています 、2つの問題があります :

    1。) あなたはこれを求めませんでしたが、表現は信頼できません。その結果は、クエリが実行されているセッションの現在のタイムゾーン設定によって異なります。詳細はこちら:

    式を明確にするために、次を使用できます。

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

    または、(こちらのマニュアルをお読みください)

    LOCALTIMESTAMP  -- explicitly take the local time
    

    timestamptzでの作業を検討します 代わりに。
    どちらも2番目の問題を解決しません:

    2。)質問に答えます。 制約の除外は機能しません。 ドキュメントごと:

    大胆な強調鉱山。

    now() CURRENT_TIMESTAMPのPostgres実装です 。システムカタログでわかるように、それはSTABLEだけです。 、IMMUTABLEではありません :

    SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
    
    proname | provolatile
    --------+------------
    now     | s              -- meaning: STABLE
    

    ソリューション

    1。) WHEREに定数を指定することで、制限を克服できます。 条件(常に「不変」):

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

    2。) または、不変関数を「偽造」することによって:

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

    そして:

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

    ただし、これをどのように使用するかに注意してください:while now() STABLEです (トランザクションの期間中は変更されません)、変更されます トランザクション間で変更されるため、プリペアドステートメント(パラメータ値を除く)やインデックスなど、噛み付く可能性のある場所でこれを使用しないように注意してください。

    3。) または、一見冗長な定数WHEREを追加することもできます パーティションの制約に一致する現在のクエリの句:

    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;

    now() - '1 hour'::intervalであることを確認してください 明らかに、適切なパーティションに分類されるか、結果が得られません。

    余談ですが、CHECKでこの式を使用したいと思います 制約とクエリ。取り扱いが簡単で同じことをします:

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



    1. MYSQLは値によるカウントを選択します

    2. postgresqlおよびpgadmindockerコンテナの問題

    3. MySQL-ストアドプロシージャへの入力を分解/分割

    4. Androidのarraylistからテキストの一部を太字にする方法