web-dev-qa-db-ja.com

最新のタイムスタンプを持つ行

TIMESTAMPZ 列の最新の値を持つ行を取得するにはどうすればよいですか?インデックスは必要ですか?インデックスは戦略を変えますか?動作はデータベースによって異なりますか(私はPostgres 9.4を使用しています)?

私のアプリはデータフィードからデータを記録します。別のプロセスは、最新の最新のエントリを取得するために際限なくクエリを実行します。二次ソースから古いデータが表示される場合があります。したがって、最後に挿入された行は通常、最新のデータですが、必ずしもそうとは限りません。

私はこの種類のSQLを使用しています。ここで、when_TIMESTAMP WITH TIME ZONE列です。

SELECT *
FROM my_table_ 
ORDER BY when_ DESC
LIMIT 1
;

このコードは機能します(データにNULL値がない場合!)。しかし、数百万行になる可能性があり、10秒ごとにクエリが実行されるため、パフォーマンスが心配です。

when_列にインデックスがない場合、このステートメントはすべての行のフルスキャンを必要としますか?

インデックスを追加するとパフォーマンスが変わりますか? Postgresは自動的にインデックスをスキャンして最新の行を見つけますか、それともインデックススキャンを実行するために何かをする必要がありますか?

when_列にインデックスがある場合、このSQLを変更してクエリの他のアプローチ/戦略を使用する必要がありますか?

新しく挿入された行を収集する他の方法はありますか?私は主キーに SERIAL types ではなく [〜#〜] uuid [〜#〜] を使用しており、複数のデータベースインスタンス間でデータを統合できるため、ルール増え続ける整数をチェックする。

2
Basil Bourque

基本的な答え

大きな列をいくつか選択するので(コメント内の情報) index-only scan はおそらくnot実行可能なオプション。

このコードは機能します(データにNULL値がない場合!)

NULLS LASTを追加して、NULL値であっても機能するようにします。追加された条項はどちらの方法でも害を及ぼすことはありません。理想的には、付随するインデックスでもこの句を使用します。

SELECT <some big columns>
FROM   my_table_ 
ORDER  BY when_ DESC NULLS LAST
LIMIT  1;

when_列にインデックスがない場合、このステートメントはすべての行のフルスキャンを必要としますか?

はい。インデックスがなければ、他に選択肢はありません。

when_列にインデックスがある場合、このSQLを変更してクエリの他のアプローチ/戦略を使用する必要がありますか?

基本的に、これは完璧なクエリです。高度なインデックス作成と組み合わせて、より多くのオプションがあります。

高度なテクニック

後のwhen_を含む行の一定の流入があります。最新の_whenが常に増加すると仮定し、決して(またはまれに)減少(最新の行が削除/更新)、非常に小さい部分インデックスを使用できます。

基本的な実装

  1. クエリを1回実行して最新のwhen_を取得し、安全なマージンを差し引いて(最新の行が失われないようにするため)、IMMUTABLEを作成しますその周りの機能。基本的に「偽のグローバル定数」:

    CREATE OR REPLACE FUNCTION f_latest_when()
      RETURNS timestamptz LANGUAGE sql COST 1 IMMUTABLE AS
    $$SELECT timestamptz '2015-07-25 01:00+02'$$;
  2. 古い行をすべて除外して部分インデックスを作成します(必要に応じて安全なマージンを差し引いてください)。

    CREATE INDEX my_table_when_idx ON my_table_ (when_ DESC NULLS LAST)
    WHERE when_ > f_latest_when();

    数百万行の場合、サイズの違いは劇的になります。

  3. 関連するすべてのクエリで関数を使用します。同じWHERE条件を(必要に応じて冗長に)含めて、クエリプランナーにインデックスが適用されることを納得させます。単純なクエリの場合:

    SELECT <some big columns>
    FROM   my_table_ 
    WHERE when_ > f_latest_when()
    ORDER  BY when_ DESC NULLS LAST
    LIMIT  1;

インデックスのサイズは、新しい(後の)エントリとともに大きくなります。同時アクセスがないかほとんどない場合に、後のタイムスタンプと適切なタイミングでREINDEXを使用して関数を再作成します。関連する行数が追加された後にのみ、インデックスを再作成します。通常、数千のエントリはそれほど重要ではありません。 何百万を切り捨てるためにこれを行っています。
その美しさ:クエリはまったく変更する必要がありません。

高度な実装SOに関するこの関連する回答で部分インデックスを自動的に更新する機能:

より一般的なアドバイスと密接に関連しています:

4