# Средняя стоимость перелета

    => EXPLAIN SELECT avg(amount) FROM ticket_flights;

                                                 QUERY PLAN
    ----------------------------------------------------------------------------------------------------
     Finalize Aggregate  (cost=110786.07..110786.08 rows=1 width=32)
       ->  Gather  (cost=110785.85..110786.06 rows=2 width=32)
             Workers Planned: 2
             ->  Partial Aggregate  (cost=109785.85..109785.86 rows=1 width=32)
                   ->  Parallel Seq Scan on ticket_flights  (cost=0.00..101044.27 rows=3496628 width=6)
    (5 rows)

Планировщик выбирает параллельный план.

# Общее табличное выражение

    => EXPLAIN
      WITH tf AS ( SELECT * FROM ticket_flights )
      SELECT avg(amount) FROM tf;

                                        QUERY PLAN
    ----------------------------------------------------------------------------------
     Aggregate  (cost=338814.95..338814.96 rows=1 width=32)
       CTE tf
         ->  Seq Scan on ticket_flights  (cost=0.00..149997.06 rows=8391906 width=32)
       ->  CTE Scan on tf  (cost=0.00..167838.12 rows=8391906 width=16)
    (4 rows)

Здесь узел CTE представляет подзапрос в общем табличном выражении.

Затем выполняется узел CTE Scan: по сути он работает так же, как и Seq Scan, но просматривает не таблицу, а полученный и материализованный результат выполнения подзапроса. Эта операция выполняется последовательно.

При этом сам подзапрос в общем табличном выражении может работать параллельно:

    => EXPLAIN
      WITH x AS ( SELECT avg(amount) FROM ticket_flights )
      SELECT * FROM x;

                                                     QUERY PLAN
    ------------------------------------------------------------------------------------------------------------
     CTE Scan on x  (cost=110786.08..110786.10 rows=1 width=32)
       CTE x
         ->  Finalize Aggregate  (cost=110786.07..110786.08 rows=1 width=32)
               ->  Gather  (cost=110785.85..110786.06 rows=2 width=32)
                     Workers Planned: 2
                     ->  Partial Aggregate  (cost=109785.85..109785.86 rows=1 width=32)
                           ->  Parallel Seq Scan on ticket_flights  (cost=0.00..101044.27 rows=3496628 width=6)
    (7 rows)

# Последовательный план

    => EXPLAIN SELECT * FROM flights;

                               QUERY PLAN
    ----------------------------------------------------------------
     Seq Scan on flights  (cost=0.00..4564.67 rows=214867 width=63)
    (1 row)

Размер таблицы достаточно большой, чтобы планировщик рассмотрел параллельный план:

    => SELECT pg_size_pretty(pg_table_size('flights')) size;

     size
    -------
     19 MB
    (1 row)

Используя конфигурационный параметр можно убедиться, что запрос в принципе не запрещает параллельное выполнение, но планировщик отказывается от такой возможности из-за ее неэффективности:

    => SET force_parallel_mode = on;

    SET

    => EXPLAIN SELECT * FROM flights;

                                  QUERY PLAN
    ----------------------------------------------------------------------
     Gather  (cost=1000.00..27051.37 rows=214867 width=63)
       Workers Planned: 1
       Single Copy: true
       ->  Seq Scan on flights  (cost=0.00..4564.67 rows=214867 width=63)
    (4 rows)

В данном случае дело в том, что пересылка всех строк таблицы между процессами невыгодна.