3

したがって、約150万行のテーブルがあり、次のようになります。

name   | time       | data1 | data2  
--------------------------------------
 93-15 | 1337348782 |   11  | 60.791 
 92-02 | 1337348783 |   11  | 62.584 
 92-02 | 1337348056 |   11  | 63.281
 93-15 | 1337348068 |    8  | 65.849
 92-02 | 1337348117 |   11  | 63.271 
 93-15 | 1337348129 |    8  | 65.849 
 92-02 | 1337348176 |   10  | 63.258 
 93-15 | 1337348188 |    8  | 65.849 
 92-02 | 1337348238 |   10  | 63.245 
 93-15 | 1337348248 |    8  | 65.849  

...これらは、監視が必要なものからの履歴ステータスの更新に対応します。さて、私がやりたいのは、各ユニットの現在のステータスを見つけることです。

ここスタックオーバーフローで同様の質問を見つけるのは難しくありませんでした。そして、調査結果から外挿して、私はこの質問を思いつきました:

SELECT * FROM vehicles v
  JOIN ( SELECT  MAX(time) as max, name
    FROM vehicles
    GROUP BY name)
  m_v
ON (v.time = m_v.max AND v.name = m_v.name);

しかし、約150万行(およびカウント)があるので、より高速なクエリを可能にする別のアプローチはありますか?

4

1 に答える 1

6
WITH
  sequenced_data
AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY name ORDER BY time DESC) AS sequence_id,
    *
  FROM
    vehicles
)
SELECT
  *
FROM
  sequenced_data
WHERE
  sequence_id = 1

のカバーインデックス(name, time)も役立ちます。


編集:それがどのように機能するかなどに関するメモ。

PostgreSQLには、ウィンドウ関数または分析関数として知られているものがあります。これらは通常、の形式を取りsome_function() OVER (PARTITION BY some_fields ORDER BY some_fields)ます。

この場合、私はを使用しROW_NUMBER() OVER (PARTITION BY name ORDER BY time DESC)ました。

ROW_NUMBER()データセットに一意の行番号を作成します。 1 to n記録のためn

PARTITION BY nameこれは、この関数が異なる名前に独立して適用されることを意味します。それぞれnameが独自のグループ/ウィンドウ/パーティションであり、グループ/ウィンドウ/パーティションごとにROW_NUMBER()最初からやり直した結果です。1

ORDER BY time DESC関数が適用される前に、 1つのグループ/ウィンドウ/パーティション内のすべてのレコードを取得し、timeフィールドごとに順序付けします。最も高い値が最初になります。ROW_NUMBER()

したがって、サンプルデータの場合、これを取得します...

 name  | time       | data1 | data2  | row_number
--------------------------------------------------

 92-02 | 1337348783 |   11  | 62.584 | 1
 92-02 | 1337348238 |   10  | 63.245 | 2
 92-02 | 1337348176 |   10  | 63.258 | 3
 92-02 | 1337348117 |   11  | 63.271 | 4
 92-02 | 1337348056 |   11  | 63.281 | 5

 93-15 | 1337348782 |   11  | 60.791 | 1
 93-15 | 1337348248 |    8  | 65.849 | 2
 93-15 | 1337348188 |    8  | 65.849 | 3
 93-15 | 1337348129 |    8  | 65.849 | 4
 93-15 | 1337348068 |    8  | 65.849 | 5

順序はtime DESCであるため、各グループ/ウィンドウ/パーティションで最も値の高いtimeフィールドnameは常に。row_numberになり1ます。

インデックスをオンに(name, time)すると、データがわかりやすい順序になっていることを確認できるため、オプティマイザーにとって非常に簡単になります。これは、ROW_NUMBER()実際にはすべてのレコードに適用されるわけではないことを意味します。最も価値の高いレコードを見つけてtime割り当てるとすぐにROW_NUMBER() = 1、停止して次のレコードに進むことができることがわかりnameます。

于 2012-05-18T14:23:18.337 に答える