ORDER BY ASC is 300x faster than ORDER BY DESC The ascending sort is 300x faster than descending sort on a column which has a B-Tree index.
I have table of around 20 million rows.
I have indexes on inserted_at and x columns.

Ascending Sort

select 
  * from table_a a where
  a.inserted_at &gt;= '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)
  -&gt;  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 &gt;= '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 &gt;= '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
  -&gt;  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 &gt;= '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


Descending sort

select 
  * from table_a a where
  a.inserted_at &gt;= '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)
  -&gt;  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 &gt;= '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 &gt;= '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
  -&gt;  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 &gt;= '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


What could be the problem?
I think the problem is two-fold (or 3-fold):


missing composite index on both columns filtered: (x, inserted_at)
uneven distribution
old statistics



   Filter: (a.x = 'some_x_val'::uuid)
   Rows Removed by Filter: 2745418



The unusual distribution means that the single index scan has to do a lot of work to remove the rows that don't match the 2nd filter (by the other (x) column). The index scan for ORDER BY ASC is just lucky and finds the 20 rows a bit more quickly, only by luck. It could be the other way around with other values in the parameters of inserted_at and x

So the best way to solve this is to add this composite index. You could follow the advice on the linked question and answer by Erwin, to update statistics on the table but this may help with the issue or not. It's not certain.