ええと、両方のクエリは異なるテーブルにあります( 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以降で。それはよりクリーンで少し速いです。参照: