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

PostgreSQLウィンドウ関数:比較によるパーティション

    いくつかの異なるウィンドウ関数と2つのサブクエリを使用すると、これはまともな速度で動作するはずです:

    WITH events(id, event, ts) AS (
      VALUES
       (1, 12, '2014-03-19 08:00:00'::timestamp)
      ,(2, 12, '2014-03-19 08:30:00')
      ,(3, 13, '2014-03-19 09:00:00')
      ,(4, 13, '2014-03-19 09:30:00')
      ,(5, 12, '2014-03-19 10:00:00')
       )
    SELECT first_value(pre_id)  OVER (PARTITION BY grp ORDER BY ts)      AS pre_id
         , id, ts
         , first_value(post_id) OVER (PARTITION BY grp ORDER BY ts DESC) AS post_id
    FROM  (
       SELECT *, count(step) OVER w AS grp
       FROM  (
          SELECT id, ts
               , NULLIF(lag(event) OVER w, event) AS step
               , lag(id)  OVER w AS pre_id
               , lead(id) OVER w AS post_id
          FROM   events
          WINDOW w AS (ORDER BY ts)
          ) sub1
       WINDOW w AS (ORDER BY ts)
       ) sub2
    ORDER  BY ts;
    

    tsの使用 タイムスタンプ列の名前として。
    tsを想定 一意である-そしてインデックス付き (一意の制約が自動的にそれを行います)。

    5万行の生命表を使用したテストでは、単一のインデックススキャンのみが必要でした。 。したがって、大きなテーブルでもかなり高速である必要があります。比較すると、join /distinctを使用したクエリは1分後に終了しませんでした(予想どおり)。
    最適化されたバージョンでも、一度に1つのクロス結合を処理します(制限条件がほとんどない左側の結合は事実上制限されています)クロスジョイン)は1分後に終了しませんでした。

    大きなテーブルで最高のパフォーマンスを得るには、特に work_memのメモリ設定を調整してください (大規模なソート操作の場合)。 RAMを節約できる場合は、セッション用に一時的に(はるかに)高く設定することを検討してください。詳しくはこちらとこちらをご覧ください。

    どのように?

    1. サブクエリsub1 前の行のイベントを確認し、それが変更された場合にのみ保持して、新しいグループの最初の要素をマークします。同時に、idを取得します 前の行と次の行の(pre_idpost_id

    2. サブクエリsub2count() null以外の値のみをカウントします。結果のgrp 連続する同じイベントのブロックでピアをマークします。

    3. 最後のSELECT 、最初のpre_idを取得します 最後のpost_id 各行のグループごとに、目的の結果に到達します。
      実際には、これは外側のSELECTでさらに高速になるはずです。 :

       last_value(post_id) OVER (PARTITION BY grp ORDER BY ts
                                 RANGE BETWEEN UNBOUNDED PRECEDING
                                       AND     UNBOUNDED FOLLOWING) AS post_id
      

      ...ウィンドウの並べ替え順序がpre_idのウィンドウと一致するため 、したがって、必要なソートは1つだけです。簡単なテストで確認できるようです。このフレーム定義の詳細。

    SQLフィドル。




    1. GI12.1.0.2とセグメンテーション違反をコンパイルできません

    2. ビューのSELECTには、FROM句にサブクエリが含まれています

    3. 整合性制約違反:1452子行を追加または更新できません:

    4. MySQL8.0で変更されたロールの使用方法