0

タイム スライス データが必要な約 800 万行のテーブルがあります。
PostgreSQL 9.1 を使用しています。

日ごとに、各「object_id」(リストを指定) に関連付けられた max(start_time) の「data」値の合計をこのテーブルに照会する必要があります。(つまり、特定のリストの object_id ごとに、1 日の終わりに最も近いレコード)。

基本的なテーブル構造は次のとおりです。

CREATE TABLE checks (
  id SERIAL PRIMARY KEY,
  object_id INTEGER,
  state INTEGER,
  start_time TIMESTAMP,
  data TEXT
);

dataTEXTフィールドですが、値がありますnumeric(この側面を変更することはできませんが、キャストを使用して変換できます)。

そして、これが私がこれまでに取り組んでいるクエリです:

WITH object_ids AS ( 
    SELECT object_id FROM objects WHERE object_id in (14845,12504,12451,12452)
),
records AS (
    SELECT
        data,
        start_time,
        MAX(start_time) OVER (PARTITION BY object_id)
    FROM checks
    WHERE
        object_id IN (SELECT object_id FROM object_ids) AND
        state = 0 AND
        start_time BETWEEN '2013-05-01 00:00:00' AND '2013-05-02 00:00:00'
)   
SELECT 
    SUM(data::bigint) 
FROM   
    records
WHERE 
    max = start_time

このクエリを毎月実行して、一連のグラフ データ ポイントを取得します。

このクエリを変更して、1 日ごとに個別のクエリを実行する必要がないようにしたいのですが、1 つのクエリで 1 日あたりの値のセットを返します。

start_time          | sum
---------------------------
2013-05-01 00:00:00 | 39118
2013-05-02 00:00:00 | 98387
2013-05-03 00:00:00 | 8384

私はタイム スライスの質問を調査してきましたが、それらは非常に役に立ちます (StackOverflow に対してウィンドウ関数を使用しているという事実を負っています!) が、この問題を解決するために飛躍することはできません。

4

2 に答える 2

1
SELECT day, sum(data) AS total_per_day
FROM  (
   SELECT DISTINCT ON (object_id, 1)
          start_time::date, data::numeric
   FROM   checks c
   WHERE  object_id in (14845,12504,12451,12452)
   AND    state = 0
   AND    start_time >= '2013-04-01'::date
   AND    start_time <  '2013-05-05'::date   -- any range of days
   ORDER  BY object_id, 1, c.start_time DESC -- seems redundant, see text
   ) x
GROUP BY  1
ORDER BY  1

これにより、合計で1行の日が得られます。@Clodoaldo が既に投稿したものとよく似ていることに気づきましたが、正しいDISTINCT ON構文に加えて、その他の改善点と必要な説明を示します。

  • DISTINCT ON1日あたりのデータ値に使用できます。ウィンドウ関数よりもシンプルで高速である必要があります。

  • ORDER BY句は式に同意する必要がありDISTINCT ONます(リンクされた回答の詳細)。その理由は次のとおりです。

    ORDER  BY 1, start_time::date, start_time DESC
    

    2 番目の項目は冗長に見えますが、ここでは必要です。

  • dateから を取得し、timestampキャストするだけです: start_time::date

  • リストに含めるときは注意してくださいstart_time::date(私はこれを最適化しました) SELECTGROUP BY入力列と出力列はORDER BY、入力列よりも優先されます (入力列のみを参照できる場合WHEREとは対照的に)。HAVING出力列に別のエイリアスを使用するか、ベース列を参照するにはテーブル修飾する必要があります。c.start_time

  • あなたと一緒timestampに、実際には常に上の境界線を除外したいと思うでしょう。この関連する回答の詳細:

于 2013-05-08T01:52:17.557 に答える