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

インデックスにヒットするdate_partクエリを取得するにはどうすればよいですか?

    ええと、両方のクエリは異なるテーブルにあります( reportimpression vs. reportimpressionday )、したがって、2つのクエリの比較は実際には比較ではありません。 ANALYZEしましたか 両方?さまざまな列統計も役割を果たす可能性があります。インデックスまたはテーブルの肥大化は異なる場合があります。すべての行の大部分が2019年2月の対象になりますか?など

    暗闇の中でのワンショット、両方のテーブルのパーセンテージを比較します:

    SELECT tbl, round(share * 100 / total, 2) As percentage
    FROM  (
       SELECT text 'reportimpression' AS tbl
            , count(*)::numeric AS total
            , count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')::numeric AS share
       FROM  reportimpression
    
       UNION ALL
       SELECT 'reportimpressionday'
            , count(*)
            , count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')
       FROM  reportimpressionday
      ) sub;
    

    reportimpression用のものです より大きい?その場合、インデックスが役立つと予想される数を超える可能性があります。

    通常、インデックスは reportimpression_datelocal_index on(datelocal)はそれに適しているようで、 reportimpression_viewership_index 自動バキュームがテーブルの書き込み負荷を上回った場合でも、インデックスのみのスキャンを許可します。 (インプレッション agegroup これは死んだ貨物であり、なくてもさらにうまく機能します。

    回答

    26.6%、日は26.4% 私の質問のために。このような大きな割合の場合、インデックスは通常、まったく役に立ちません 。通常、シーケンシャルスキャンが最速の方法です。インデックスのみのスキャンのみ可能 基になるテーブルがはるかに大きい場合でも、意味があります。 (または、重大 テーブルが肥大化し、インデックスが肥大化しないため、インデックスが再び魅力的になります。)

    最初のクエリは、転換点を超えている可能性があります。インデックスのみのスキャンが表示されるまで、時間枠を狭めてみてください。すべての行の約5%以上が適格である(ビットマップ)インデックススキャンは表示されません(多くの要因によって異なります)。

    クエリ

    とはいえ、次の変更されたクエリを検討してください。

    SELECT date_part('hour', datelocal)                AS hour
         , SUM(views) FILTER (WHERE gender = 'male')   AS male
         , SUM(views) FILTER (WHERE gender = 'female') AS female
    FROM   reportimpression
    WHERE  datelocal >= '2019-02-01'
    AND    datelocal <  '2019-03-01' -- '2019-02-28'  -- ?
    GROUP  BY 1
    ORDER  BY 1;
    
    SELECT date_trunc('day', datelocal)                AS day
         , SUM(views) FILTER (WHERE gender = 'male')   AS male
         , SUM(views) FILTER (WHERE gender = 'female') AS female
    FROM   reportimpressionday
    WHERE  datelocal >= '2019-02-01'
    AND    datelocal <  '2019-03-01'
    GROUP  BY 1
    ORDER  BY 1;
    

    主なポイント

    • ローカライズされた日付形式を使用する場合 '2-1-2019'のように 、 to_timestamp() 明示的なフォーマット指定子を使用します。それ以外の場合、これはロケール設定に依存し、異なる設定のセッションから呼び出されたときに(サイレントに)中断する可能性があります。ロケール設定に依存しない、示されているISO日付/時刻形式を使用してください。

    • 1か月を含めたいようです 2月の。しかし、あなたのクエリは上限を逃しています。一つには、2月は29日あるかもしれません。 datelocal <'2-28-2019' 2月28日もすべて除外します。 datelocal <'2019-03-01'を使用します 代わりに。

    • 同じ式でグループ化して並べ替える方が安い SELECTにあるように 可能であればリストします。したがって、 date_trunc()を使用します そこにも。必要のない別の表現を使用しないでください。 必要の場合 結果の日付部分は、次のようにグループ化された式に適用します。

      SELECT date_part('day', date_trunc('day', datelocal)) AS day
      ...
      GROUP  BY date_trunc('day', datelocal)
      ORDER  BY date_trunc('day', datelocal);
      

      少しノイズの多いコードですが、高速です(クエリプランナー用に最適化するのも簡単です)。

    • 集計FILTERを使用します 条項 Postgres9.4以降で。それはよりクリーンで少し速いです。参照:




    1. ローカルホストPHPアプリケーションからのHerokuPostgres接続

    2. Extract()がPostgreSQLでどのように機能するか

    3. 接続プールを無効にする方法は?

    4. t-sqlの左結合が機能しないのはなぜですか?