2

を発生し、温度およびタイムスタンプ、ミリ秒エポック時間で毎分1つのタイムスタンプのテーブル持っている最大値と最小値を取得し、タイムスタンプ:私が持っているのPostgres:彼らは私がPostgresの9.2を実行している

weather=# \d weather_data 
     Table "public.weather_data" 
    Column |  Type  | Modifiers 
-------------+--------------+----------- 
timestamp | bigint  | not null 
sensor_id | integer  | not null 
temperature | numeric(4,1) | 
humidity | integer  | 
date  | date   | not null 
Indexes: 
    "weather_data_pkey" PRIMARY KEY, btree ("timestamp", sensor_id) 
    "weather_data_date_idx" btree (date) 
    "weather_data_humidity_idx" btree (humidity) 
    "weather_data_sensor_id_idx" btree (sensor_id) 
    "weather_data_temperature_idx" btree (temperature) 
    "weather_data_time_idx" btree ("timestamp") 
Foreign-key constraints: 
    "weather_data_sensor_id_fkey" FOREIGN KEY (sensor_id) REFERENCES weather_sensors(sensor_id) 

weather=# select * from weather_data order by timestamp desc; 
    timestamp | sensor_id | temperature | humidity | date  
---------------+-----------+-------------+----------+------------ 
1483272420000 |   2 |  22.3 |  57 | 2017-01-01 
1483272420000 |   1 |  24.9 |  53 | 2017-01-01 
1483272360000 |   2 |  22.3 |  57 | 2017-01-01 
1483272360000 |   1 |  24.9 |  58 | 2017-01-01 
1483272300000 |   2 |  22.4 |  57 | 2017-01-01 
1483272300000 |   1 |  24.9 |  57 | 2017-01-01 
[...] 

をこの既存の毎日の高値と安値を取得するクエリが、その高いか低いが発生したことをない特定の時間:

WITH t AS (
    SELECT date, highest, lowest 
    FROM (
     SELECT date, max(temperature) AS highest 
     FROM weather_data 
     WHERE sensor_id = (SELECT sensor_id FROM weather_sensors WHERE sensor_name = 'outdoor') 
     GROUP BY date 
     ORDER BY date ASC 
    ) h 
    INNER JOIN (
     SELECT date, min(temperature) AS lowest 
     FROM weather_data 
     WHERE sensor_id = (SELECT sensor_id FROM weather_sensors WHERE sensor_name = 'outdoor') 
     GROUP BY date 
     ORDER BY date ASC 
    ) l 
    USING (date) 
    ORDER BY date DESC 
) 
SELECT * from t ORDER BY date ASC; 

の2つのがあり万行を超えるビットは、データベース内だと、それは〜1.2秒かかります実行する 残念な。私は今、高いか低いがあったことを特定の時刻を取得したい、私は作業を行い、この使用してウィンドウ関数、思い付いたけど〜5.6秒かかる:

SELECT h.date, high_time, high_temp, low_time, low_temp FROM (
    SELECT date, high_temp, high_time FROM (
     SELECT date, temperature AS high_temp, timestamp AS high_time, row_number() 
     OVER (PARTITION BY date ORDER BY temperature DESC, timestamp DESC) 
     FROM weather_data 
     WHERE sensor_id = (SELECT sensor_id FROM weather_sensors WHERE sensor_name = 'outdoor') 
    ) highs 
    WHERE row_number = 1 
) h 
INNER JOIN (
    SELECT * FROM (
     SELECT date, temperature AS low_temp, timestamp AS low_time, row_number() 
     OVER (PARTITION BY date ORDER BY temperature ASC, timestamp DESC) 
     FROM weather_data 
     WHERE sensor_id = (SELECT sensor_id FROM weather_sensors WHERE sensor_name = 'outdoor') 
    ) lows 
    WHERE row_number = 1 
) l 
ON h.date = l.date 
ORDER BY h.date ASC; 

をするいくつかの比較的単純な加算があります私はそれが実行時間の大量を追加しません作ることができる最初のクエリ?私はそこにあると仮定しますが、私は私が問題をあまりにも長く見ていた時点にいると思います!

+1

可能重複タイブレーカとして順序にZTIMESTAMP添加Z日付とZタイムスタンプ

  • を接頭辞 - フェッチ行の最大値を持つ行]](http://stackoverflow.com/questions/586781/postgresql-fetch-the-row-which-has-the-max-value- for a-column) – Joe

  • +1

    無関係ですが、最初のクエリの派生テーブルの 'order by 'は無駄です –

    +0

    @a_horse_with_no_name注目、ありがとう! – VirtualWolf

    答えて

    2
    SELECT 
         DISTINCT ON (zdate) zdate 
         , first_value(ztimestamp) OVER www AS stamp_at_min 
         , first_value(temperature) OVER www AS tmin 
         , last_value(ztimestamp) OVER www AS stamp_at_max 
         , last_value(temperature) OVER www AS tmax 
    FROM weather_data 
    WHERE sensor_id = 2 
    WINDOW www AS (PARTITION BY zdate ORDER BY temperature, ztimestamp 
           ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 
           ) 
         ; 
    

    • Iは、[のPostgreSQL
    +0

    それはうまく動作します、ありがとう!物事をスピードアップするために実行できる索引関連のトリッキーが追加されていますか(実行には約3.7秒かかります)、そういうものに最適化できるものはあまりないでしょうか? – VirtualWolf

    +0

    あなたのテーブルには基本的に2つの候補キーがあります:あなたのPKとおそらく{zdate、sensor_id、temperature、...}は一意ではありません。いずれにせよ、私はあなたが単一列のインデックスを取り除くべきだと思います。そしてzdate *はztimestampに機能的に依存することができます(これはintの代わりにタイムスタンプになる可能性があります) – wildplasser

    +0

    単一列インデックスの_rid_を取得していますか?面白い。私は他の(より単純な)無関係なクエリをいくつか持っていますが、このテーブルではインデックスがなくても非常に遅くなると思います。 – VirtualWolf

    2

    これはあなたの2番目のクエリと同じことが、唯一のweather_dataテーブル上の単一のスキャン必要があります:それは結果に(別名「ピボット」)クエリクロス集計を行うには、条件付き集約を使用しています

    select date, 
         max(case when high_rn = 1 then timestamp end) as high_time, 
         max(case when high_rn = 1 then temperature end) as high_temp, 
         max(case when low_rn = 1 then timestamp end) as low_time, 
         max(case when low_rn = 1 then temperature end) as low_temp 
    from (
        select timestamp, temperature, date, 
         row_number() OVER (PARTITION BY date ORDER BY temperature DESC, timestamp DESC) as high_rn, 
         row_number() OVER (PARTITION BY date ORDER BY temperature ASC, timestamp DESC) as low_rn 
        from weather_data 
        where sensor_id = ... 
    ) t 
    where (high_rn = 1 or low_rn = 1) 
    group by date; 
    

    をその最低温度と最高温度のみが含まれています。


    関連のない、しかし:datetimestampは列のために恐ろしい名前です。 1つはキーワードなので、もっと重要なのは列の実際の意味を文書化していないからです。それは「期日」ですか? 「読書日」? 「処理日」?

    +0

    ありがとう!これは、実行するには約5.2秒かかり、上記の場合は3.7秒かかります。列の名前は、その特定の温度の読み値が取られたすべての時間と日付なので、私は日付と読み込み時間を読むと思います。それは個人的なプロジェクトであり、私はそれに取り組んでいるだけです(私の家の内外の現在の温度を保つだけです)。 :) – VirtualWolf

    +0

    気温センサが時々変わって私のアプリケーションに21.8の値を送るので、私はちょうど 'temperature!= 21.8'を追加する必要があることを思い出しました。 @ wildplasserのクエリを実行するウィンドウ関数のサブクエリを追加し、単純な 'where temperature!= 21.8'をあなたのものに加えると、彼らはお互いに約100ms以内にいます! – VirtualWolf

    関連する問題