昇順のソートは、Bツリーインデックスを持つ列での降順のソートより300倍高速です。約2,000万行のテーブルがあります。inserted_at
およびx
列。
select
* from table_a a where
a.inserted_at >= '2018-09-01 00:00:00.0' and a.x in ('some_x_val')
order by a.inserted_at asc
offset 0 limit 20;
Limit (cost=0.44..2027.69 rows=20 width=51) (actual time=418.529..464.558 rows=20 loops=1)
-> Index Scan using table_a_inserted_at_index on table_a a (cost=0.44..5406390.18 rows=53337 width=51) (actual time=418.527..464.543 rows=20 loops=1)
Index Cond: (inserted_at >= '2018-09-01 00:00:00'::timestamp without time zone)
Filter: (event_type_id = ''some_x_val'::uuid)
Rows Removed by Filter: 4092
Planning time: 0.177 ms
Execution time: 464.596 ms
explain (analyze, verbose, buffers) select * from table_a a where a.inserted_at >= '2018-09-01 00:00:00.0' and a.x in ('some_x_val') order by a.inserted_at asc offset 0 limit 20;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.44..2027.77 rows=20 width=51) (actual time=527.032..575.516 rows=20 loops=1)
Output: x, y, z
Buffers: shared hit=2492 read=905
-> Index Scan using table_a_inserted_at_index on public.table_a a (cost=0.44..5406596.96 rows=53337 width=51) (actual time=527.029..575.496 rows=20 loops=1)
Output: x, y, z
Index Cond: (a.inserted_at >= '2018-09-01 00:00:00'::timestamp without time zone)
Filter: (a.x = 'some_x_val'::uuid)
Rows Removed by Filter: 4092
Buffers: shared hit=2492 read=905
Planning time: 0.162 ms
Execution time: 575.550 ms
select
* from table_a a where
a.inserted_at >= '2018-09-01 00:00:00.0' and a.x in ('some_x_val')
order by a.inserted_at desc
offset 0 limit 20;
Limit (cost=0.44..2027.69 rows=20 width=51) (actual time=148377.757..148385.703 rows=20 loops=1)
-> Index Scan Backward using table_a_inserted_at_index on table_a a (cost=0.44..5406383.67 rows=53337 width=51) (actual time=148377.756..148385.691 rows=20 loops=1)
Index Cond: (inserted_at >= '2018-09-01 00:00:00'::timestamp without time zone)
Filter: (x = 'some_x_val'::uuid)
Rows Removed by Filter: 2737952
Planning time: 0.663 ms
Execution time: 148385.756 ms
explain (analyze, verbose, buffers) select * from table_a a where a.inserted_at >= '2018-09-01 00:00:00.0' and a.x in ('some_x_val') order by a.inserted_at desc offset 0 limit 20;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.44..2027.77 rows=20 width=51) (actual time=168306.377..168312.296 rows=20 loops=1)
Output: x, y, z
Buffers: shared hit=2439002 read=359523 dirtied=288
-> Index Scan Backward using table_a_inserted_at_index on public.table_a a (cost=0.44..5406596.96 rows=53337 width=51) (actual time=168306.375..168312.282 rows=20 loops=1)
Output: x, y, z
Index Cond: (a.inserted_at >= '2018-09-01 00:00:00'::timestamp without time zone)
Filter: (a.x = 'some_x_val'::uuid)
Rows Removed by Filter: 2745418
Buffers: shared hit=2439002 read=359523 dirtied=288
Planning time: 0.139 ms
Execution time: 168312.326 ms
何が問題でしょうか?
問題は2つ(または3つ)だと思います。
(x, inserted_at)
Filter: (a.x = 'some_x_val'::uuid) Rows Removed by Filter: 2745418
異常な分布は、単一のインデックススキャンが2番目のフィルター(他の(x
)列による)に一致しない行を削除するために多くの作業を行う必要があることを意味します。 ORDER BY ASC
のインデックススキャンは幸運であり、運が良ければ、20行が少し早く見つかります。 inserted_at
およびx
のパラメーターの他の値と逆になる可能性があります
したがって、これを解決する最良の方法は、この複合インデックスを追加することです。リンクされた質問のアドバイスに従い、Erwinから回答を得て、テーブルの統計を更新できますが、これで問題が解決する場合とそうでない場合があります。確かではありません。