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

PostgreSQL:クエリの行数を「分単位」で実行

    アクティビティで数分だけ返す

    最短

    SELECT DISTINCT
           date_trunc('minute', "when") AS minute
         , count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
    FROM   mytable
    ORDER  BY 1;
    

    date_trunc()を使用します 、必要なものを正確に返します。

    idを含めないでください GROUP BY を実行したいので、クエリで 分のスライス。

    count() 通常、単純な集計関数として使用されます。 OVERを追加する 句はそれをウィンドウ関数にします。 PARTITION BYを省略します ウィンドウ定義で-すべての行の実行カウントが必要です 。デフォルトでは、 ORDER BY で定義されているように、現在の行の最初の行から最後のピアまでカウントされます。 。マニュアル:

    デフォルトのフレーミングオプションはRANGEUNBOUNDED PRECEDINGです。 、これはUNBOUNDEDPRECEDINGとCURRENTROWの間の範囲と同じです。 。 ORDER BYを使用 、これにより、フレームは、パーティションの開始から現在の行の最後の ORDER BYまでのすべての行に設定されます。 ピア。

    そして、それはたまたま正確に 必要なもの。

    count(*)を使用する count(id)ではなく 。それはあなたの質問(「行数」)によりよく適合します。通常、わずかに速い count(id)より 。そして、 id NOT NULLです 、質問で指定されていないため、 count(id) 間違っている 、厳密に言えば、NULL値は count(id)ではカウントされないためです。 。

    GROUP BYはできません 同じクエリレベルでの分のスライス。集計関数はに適用されます ウィンドウ関数、ウィンドウ関数 count(*) この方法では、1分あたり1行しか表示されません。
    ただし、 SELECT DISTINCT DISTINCT に適用されます ウィンドウ関数。

    ORDER BY 1 ORDER BY date_trunc('minute'、 "when")の省略形です。 ここ。
    1 SELECTの最初の式への位置参照参照です リスト。

    to_char()を使用する 結果をフォーマットする必要がある場合。いいね:

    SELECT DISTINCT
           to_char(date_trunc('minute', "when"), 'DD.MM.YYYY HH24:MI') AS minute
         , count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
    FROM   mytable
    ORDER  BY date_trunc('minute', "when");
    

    最速

    SELECT minute, sum(minute_ct) OVER (ORDER BY minute) AS running_ct
    FROM  (
       SELECT date_trunc('minute', "when") AS minute
            , count(*) AS minute_ct
       FROM   tbl
       GROUP  BY 1
       ) sub
    ORDER  BY 1;
    

    上記とよく似ていますが:

    サブクエリを使用して、1分あたりの行数を集計およびカウントします。このようにして、 DISTINCTなしで1分あたり1行を取得します 外側のSELECT

    sum()を使用する サブクエリからのカウントを合計するためのウィンドウ集計関数として。

    これは、1分あたりの行数が多いため、大幅に高速であることがわかりました。

    アクティビティのない分を含める

    最短

    @GabiMeはコメントで、すべてのeone行を取得する方法を尋ねました イベントが発生しなかった(ベーステーブルに行がない)時間を含む時間枠内:

    SELECT DISTINCT
           minute, count(c.minute) OVER (ORDER BY minute) AS running_ct
    FROM  (
       SELECT generate_series(date_trunc('minute', min("when"))
                            ,                      max("when")
                            , interval '1 min')
       FROM   tbl
       ) m(minute)
    LEFT   JOIN (SELECT date_trunc('minute', "when") FROM tbl) c(minute) USING (minute)
    ORDER  BY 1;
    

    generate_series()を使用して、最初のイベントと最後のイベントの間の時間枠で1分ごとに行を生成します -ここでは、サブクエリからの集計値に直接基づいています。

    LEFT JOIN 分とカウントに切り捨てられたすべてのタイムスタンプに。 NULL 値(行が存在しない場合)は実行カウントに追加されません。

    最速

    CTEの場合:

    WITH cte AS (
       SELECT date_trunc('minute', "when") AS minute, count(*) AS minute_ct
       FROM   tbl
       GROUP  BY 1
       ) 
    SELECT m.minute
         , COALESCE(sum(cte.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
    FROM  (
       SELECT generate_series(min(minute), max(minute), interval '1 min')
       FROM   cte
       ) m(minute)
    LEFT   JOIN cte USING (minute)
    ORDER  BY 1;
    

    繰り返しになりますが、最初のステップで1分あたりの行数を集計してカウントします。これにより、後の DISTINCTが不要になります。 。

    count()とは異なります 、 sum() NULLを返すことができます 。デフォルトは0 COALESCEを使用 。

    多くの行と"when"のインデックス サブクエリを含むこのバージョンは、Postgres 9.1-9.4でテストしたいくつかのバリアントの中で最速でした:

    SELECT m.minute
         , COALESCE(sum(c.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
    FROM  (
       SELECT generate_series(date_trunc('minute', min("when"))
                            ,                      max("when")
                            , interval '1 min')
       FROM   tbl
       ) m(minute)
    LEFT   JOIN (
       SELECT date_trunc('minute', "when") AS minute
            , count(*) AS minute_ct
       FROM   tbl
       GROUP  BY 1
       ) c USING (minute)
    ORDER  BY 1;
    



    1. サーバー側の拡張機能を構築するためにpostgresql-server-dev-X.Yをインストールするか、クライアント側のアプリケーションを構築するためにlibpq-devをインストールする必要があります

    2. トレースフラグ2389と新しいカーディナリティ推定量

    3. Oracle10gでの集計文字列の連結

    4. カーソルからデータにアクセスする前に、カーソルが正しく初期化されていることを確認してください