2

Я ожидал новых функций PostgreSQL 9.5 и очень скоро обновил нашу базу данных. Но я был очень удивлен, когда я обнаружил, чтоПочему CUBE, ROLLUP и GROUPING SETS PostgreSQL 9.5 будут медленнее, чем эквивалент UNION?

SELECT col1, col2, count(*), grouping(col1,col2) 
FROM table1 
GROUP BY CUBE(col1, col2) 

запроса на нашем наборе данных на самом деле работает гораздо медленнее (~ 3 секунды), чем сумма длительностей запросов для эквивалентных данных (~ 1second общий для всех 4-х запросов, 100-300ms каждый). Оба столбца col1 и col2 имеют на них индексы.

Ожидается ли это (что означает, что функция больше связана с совместимостью, чем с производительностью прямо сейчас)? Или это может быть изменено?

Вот пример на вакуумированной производственной таблице:

> explain analyze select service_name, state, res_id, count(*) from bookings group by rollup(service_name, state, res_id); 
                  QUERY PLAN 
------------------------------------------------------------------------------------------------------------------------------- 
GroupAggregate (cost=43069.12..45216.05 rows=4161 width=24) (actual time=1027.341..1120.675 rows=428 loops=1) 
    Group Key: service_name, state, res_id 
    Group Key: service_name, state 
    Group Key: service_name 
    Group Key:() 
    -> Sort (cost=43069.12..43490.18 rows=168426 width=24) (actual time=1027.301..1070.321 rows=168426 loops=1) 
     Sort Key: service_name, state, res_id 
     Sort Method: external merge Disk: 5728kB 
     -> Seq Scan on bookings (cost=0.00..28448.26 rows=168426 width=24) (actual time=0.079..147.619 rows=168426 loops=1) 
Planning time: 0.118 ms 
Execution time: 1122.557 ms 
(11 rows) 

> explain analyze select service_name, state, res_id, count(*) from bookings group by service_name, state, res_id 
UNION ALL select service_name, state, NULL, count(*) from bookings group by service_name, state 
UNION ALL select service_name, NULL, NULL, count(*) from bookings group by service_name 
UNION ALL select NULL, NULL, NULL, count(*) from bookings; 
                   QUERY PLAN 
----------------------------------------------------------------------------------------------------------------------------------------- 
Append (cost=30132.52..118086.91 rows=4161 width=32) (actual time=208.986..706.347 rows=428 loops=1) 
    -> HashAggregate (cost=30132.52..30172.12 rows=3960 width=24) (actual time=208.986..209.078 rows=305 loops=1) 
     Group Key: bookings.service_name, bookings.state, bookings.res_id 
     -> Seq Scan on bookings (cost=0.00..28448.26 rows=168426 width=24) (actual time=0.022..97.637 rows=168426 loops=1) 
    -> HashAggregate (cost=29711.45..29713.25 rows=180 width=20) (actual time=195.851..195.879 rows=96 loops=1) 
     Group Key: bookings_1.service_name, bookings_1.state 
     -> Seq Scan on bookings bookings_1 (cost=0.00..28448.26 rows=168426 width=20) (actual time=0.029..95.588 rows=168426 loops=1) 
    -> HashAggregate (cost=29290.39..29290.59 rows=20 width=11) (actual time=181.955..181.960 rows=26 loops=1) 
     Group Key: bookings_2.service_name 
     -> Seq Scan on bookings bookings_2 (cost=0.00..28448.26 rows=168426 width=11) (actual time=0.030..97.047 rows=168426 loops=1) 
    -> Aggregate (cost=28869.32..28869.33 rows=1 width=0) (actual time=119.332..119.332 rows=1 loops=1) 
     -> Seq Scan on bookings bookings_3 (cost=0.00..28448.26 rows=168426 width=0) (actual time=0.039..93.508 rows=168426 loops=1) 
Planning time: 0.373 ms 
Execution time: 706.558 ms 
(14 rows) 

общее время сравнимо, но последний использует четыре сканирования, она не должна быть медленнее? «Внешнее слияние на диске» при использовании rollup() странно, у меня есть work_mem, установленный на 16M.

+4

Покажите нам планы выполнения, используя 'объяснение (анализ, подробный)' –

+0

. CUBE() на тех же столбцах дает еще более резкое различие – codesnik

+1

Сортировка (внешний сортировка слияния) занимает большую часть времени, не так ли? 1027+ мс, или я неправильно понял это? –

ответ

1

Интересно, но в этом конкретном примере SET work_mem='32mb' избавляется от слияния диска, и теперь использование ROLLUP в 2 раза быстрее, чем соответствующий союз.

объяснить анализ теперь содержит: «Сортировку Метода: QuickSort Память: 19301kB»

я до сих пор удивляюсь, почему так много памяти, необходимой для простых 400 строк вывода, и поэтому слияние диска необходим 7Mb по сравнению с 19Mb памяти (сортировки накладные расходы?), но моя проблема решена.

+0

Сортировка работает на строках 168k, не так ли? –

+0

Да, ты прав. И это весь стол! Означает ли это, что ROLLUP/CUBE/GROUPING SETS могут работать только в таком (более или менее) наивном способе, или существуют ли экстремальные случаи, когда это имеет смысл? – codesnik

0

Похоже, что в наборах группировок всегда есть GroupAggregate with Sort в плане запроса. Но стандартная группа по частоте использования HashAggragate.