3

数百万行を含むテーブルがあります。このテーブルには式インデックスがあります (効果があるかどうかを確認するために、両方の方向を作成しました。

CREATE INDEX ON statuses (date_trunc('hour', created_at) ASC)
CREATE INDEX ON statuses (date_trunc('hour', created_at) DESC)

グループを使用して 1 時間ごとにステータスの数を収集するクエリを作成しようとしていますが、今日 (または過去 7 日間など) に作成されたステータスのみを対象としています。ただし、特定の日付より前にすべてのエントリを削除しようとすると、インデックスは使用されず、代わりにすべての行がフィルター処理されます。ただし、大なりを削除して等号を使用すると、インデックスが使用されます。以下の出力を入れましたEXPLAIN。このクエリでインデックスを使用するか、少なくともパフォーマンスを改善して、秒単位ではなくミリ秒単位になるように誰かが助けてくれることを願っています。

equals を使用すると、インデックスが正しく使用されます。

=> EXPLAIN ANALYSE SELECT date_trunc('hour', created_at) as hour, COUNT(*) FROM statuses GROUP BY hour HAVING date_trunc('hour', created_at) = '2013-02-06 00:00:00';
                                                                       QUERY PLAN                                                                        
---------------------------------------------------------------------------------------------------------------------------------------------------------
 GroupAggregate  (cost=132.48..29443.34 rows=1653 width=8) (actual time=4.362..4.363 rows=1 loops=1)
   ->  Bitmap Heap Scan on statuses  (cost=132.48..29419.22 rows=18337 width=8) (actual time=0.209..2.159 rows=1319 loops=1)
         Recheck Cond: (date_trunc('hour'::text, created_at) = '2013-02-06 00:00:00'::timestamp without time zone)
         ->  Bitmap Index Scan on statuses_date_trunc_idx1  (cost=0.00..131.57 rows=18337 width=0) (actual time=0.178..0.178 rows=1319 loops=1)
               Index Cond: (date_trunc('hour'::text, created_at) = '2013-02-06 00:00:00'::timestamp without time zone)
 Total runtime: 4.416 ms
(6 rows)

ただし、より大きい (またはより小さい) を使用するとすぐに、クエリはインデックスなしでテーブルのフィルターを実行します。

=> EXPLAIN ANALYSE SELECT date_trunc('hour', created_at) as hour, COUNT(*) FROM statuses GROUP BY hour HAVING date_trunc('hour', created_at) > '2013-02-06 00:00:00';
                                                              QUERY PLAN                                                              
--------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=185386.54..185772.10 rows=110160 width=8) (actual time=2915.495..2915.774 rows=21 loops=1)
   ->  Seq Scan on statuses  (cost=0.00..184164.06 rows=1222485 width=8) (actual time=1676.827..2869.748 rows=47070 loops=1)
         Filter: (date_trunc('hour'::text, created_at) > '2013-02-06 00:00:00'::timestamp without time zone)
         Rows Removed by Filter: 3620426
 Total runtime: 2916.049 ms
(5 rows)

INこの状況で選択したい地域内で 1 時間ごとに使用して一覧表示することでこれを回避できますが、インデックスがより大きいクエリに使用されていない理由を知りたいですか?

=> EXPLAIN ANALYSE SELECT date_trunc('hour', created_at) as hour, COUNT(*) FROM statuses GROUP BY hour HAVING date_trunc('hour', created_at) IN ('2013-02-06 00:00:00', '2013-02-06 01:00:00');
                                                                       QUERY PLAN                                                                        
---------------------------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=51988.38..51999.94 rows=3305 width=8) (actual time=7.218..7.223 rows=2 loops=1)
   ->  Bitmap Heap Scan on statuses  (cost=262.96..51951.70 rows=36675 width=8) (actual time=0.376..4.576 rows=2507 loops=1)
         Recheck Cond: (date_trunc('hour'::text, created_at) = ANY ('{"2013-02-06 00:00:00","2013-02-06 01:00:00"}'::timestamp without time zone[]))
         ->  Bitmap Index Scan on statuses_date_trunc_idx1  (cost=0.00..261.13 rows=36675 width=0) (actual time=0.341..0.341 rows=2507 loops=1)
               Index Cond: (date_trunc('hour'::text, created_at) = ANY ('{"2013-02-06 00:00:00","2013-02-06 01:00:00"}'::timestamp without time zone[]))
 Total runtime: 7.305 ms
(6 rows)
4

1 に答える 1

1

statusesテーブルの見積もりは、「悪い」クエリに対して返される実際の行数の26 倍です。

  1. 実行してみてくださいVACUUM ANALYZE statuses;
  2. statuses.created_atうまくいかない場合は、列の統計ターゲットを増やして、ALTER TABLE statuses ALTER created_at SET STATISTICS 500;もう一度分析してください。

これは役立つはずです。


編集:設定を確認する必要がありautovacuumます。

マニュアルのこの部分を読み、次のように設定を確認してください。

SELECT name,setting,source FROM pg_settings WHERE name ~ 'autovacuum';

テーブルが大きすぎる場合は、構文を調整autovacuum_analyze_thresholdしたり、autovacuum_analyze_scale_factor使用したりすることがありALTER TABLE tab SET (storage_parameter = ...)ます。

于 2013-02-06T21:54:56.820 に答える