[ 
https://issues.apache.org/jira/browse/HIVE-30223?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Denys Kuzmenko updated HIVE-30223:
----------------------------------
    Description: 
A reduce-side GROUP BY reads a sorted shuffle: the map side sorts its partial 
rows by key, the reducer merges the sorted runs and the GROUP BY streams over 
them. Merging SUM, COUNT, MIN and 
  MAX partials needs the rows of a partition, not their order. Trino merges 
them in a hash table over a hash-partitioned exchange and spills runs in hash 
order under memory pressure. Hive pays
  for the sort and the merge on every such edge.                                
                                                                                
                                
                                                                                
                                                                                
                                
  ReduceSinkDeDuplication also moves a second aggregation into the merge's 
reducer as a COMPLETE GROUP BY, which keeps the sort. TPC-DS q75's UNION 
DISTINCT sorts 1.92B rows on 6 keys, and the
  sort and merge take 12% of its CPU. q38 and q87 do the same for INTERSECT.    
                                                                                
                                
                                                                                
                                                                                
                                
  *Fix* ({{hive.optimize.groupby.unsorted.shuffle}}, default false)             
                                                                                
                                
  * A reduce-side GROUP BY qualifies when it merges SUM, COUNT, MIN and MAX 
partials by key (no DISTINCT, grouping sets or non-column keys) and its reducer 
does not rely on key order: up to   
  the next ReduceSinks it holds only select, filter, map join, top n key and 
hash aggregation. Such a GROUP BY reads an unordered partitioned edge with no 
sort and aggregates in a hash table. 
  The edge keeps auto-reduce.                                                   
                                                                                
                                
  * Vectorized reducers only: a reducer that does not vectorize gets its sorted 
shuffle back.                                                                   
                                
  * The vectorized reducer batches the rows of an unordered input across keys. 
Without that, every key would be forwarded as a batch of one row.               
                                 
  * When the table outgrows the hash table memory 
({{hive.map.aggr.hash.percentmemory}} of the task's) or the GC canary dies, it 
is written to a local run under the task's local dirs, in key  
  hash order (as in Trino's SpillableHashAggregationBuilder). The run is 
streamed, with no copy of the table. At close, the runs merge by hash, with 
keys sorted within a hash, through the     
  streaming mode with the same merge aggregators.                               
                                                                                
                                
  * A COMPLETE GROUP BY on all of the merge's keys, over the merge's rows 
(through selects and filters), gets one row per group and stays as it is (q38, 
q87). Otherwise it splits into a hash  
  aggregation and a merge over the unsorted partial results, and the two share 
its hash table memory (q75). A reducer that does not vectorize gets the 
COMPLETE GROUP BY back whole.            
  * A union is order-insensitive, so q38's and q87's union between the branch 
aggregation and the next hash aggregation does not disqualify the edge.         
                                  
                                                                                
                                                                                
                                
  *Measured* (TPC-DS 10 TB Parquet, 24 x r6id, same session, only the flag 
changes)                                                                        
                                     
  ||Query||off (s)||on (s)||                                                    
                                                                                
                                
  |q65|148.9|70.3|                                                              
                                                                                
                                
  |q97|100.7|73.0|                                                              
                                                                                
                                
  |q78|259.3|232.4|          

> Reduce-side GROUP BY over an unsorted shuffle
> ---------------------------------------------
>
>                 Key: HIVE-30223
>                 URL: https://issues.apache.org/jira/browse/HIVE-30223
>             Project: Hive
>          Issue Type: Improvement
>            Reporter: Denys Kuzmenko
>            Priority: Major
>
> A reduce-side GROUP BY reads a sorted shuffle: the map side sorts its partial 
> rows by key, the reducer merges the sorted runs and the GROUP BY streams over 
> them. Merging SUM, COUNT, MIN and 
>   MAX partials needs the rows of a partition, not their order. Trino merges 
> them in a hash table over a hash-partitioned exchange and spills runs in hash 
> order under memory pressure. Hive pays
>   for the sort and the merge on every such edge.                              
>                                                                               
>                                     
>                                                                               
>                                                                               
>                                     
>   ReduceSinkDeDuplication also moves a second aggregation into the merge's 
> reducer as a COMPLETE GROUP BY, which keeps the sort. TPC-DS q75's UNION 
> DISTINCT sorts 1.92B rows on 6 keys, and the
>   sort and merge take 12% of its CPU. q38 and q87 do the same for INTERSECT.  
>                                                                               
>                                     
>                                                                               
>                                                                               
>                                     
>   *Fix* ({{hive.optimize.groupby.unsorted.shuffle}}, default false)           
>                                                                               
>                                     
>   * A reduce-side GROUP BY qualifies when it merges SUM, COUNT, MIN and MAX 
> partials by key (no DISTINCT, grouping sets or non-column keys) and its 
> reducer does not rely on key order: up to   
>   the next ReduceSinks it holds only select, filter, map join, top n key and 
> hash aggregation. Such a GROUP BY reads an unordered partitioned edge with no 
> sort and aggregates in a hash table. 
>   The edge keeps auto-reduce.                                                 
>                                                                               
>                                     
>   * Vectorized reducers only: a reducer that does not vectorize gets its 
> sorted shuffle back.                                                          
>                                          
>   * The vectorized reducer batches the rows of an unordered input across 
> keys. Without that, every key would be forwarded as a batch of one row.       
>                                          
>   * When the table outgrows the hash table memory 
> ({{hive.map.aggr.hash.percentmemory}} of the task's) or the GC canary dies, 
> it is written to a local run under the task's local dirs, in key  
>   hash order (as in Trino's SpillableHashAggregationBuilder). The run is 
> streamed, with no copy of the table. At close, the runs merge by hash, with 
> keys sorted within a hash, through the     
>   streaming mode with the same merge aggregators.                             
>                                                                               
>                                     
>   * A COMPLETE GROUP BY on all of the merge's keys, over the merge's rows 
> (through selects and filters), gets one row per group and stays as it is 
> (q38, q87). Otherwise it splits into a hash  
>   aggregation and a merge over the unsorted partial results, and the two 
> share its hash table memory (q75). A reducer that does not vectorize gets the 
> COMPLETE GROUP BY back whole.            
>   * A union is order-insensitive, so q38's and q87's union between the branch 
> aggregation and the next hash aggregation does not disqualify the edge.       
>                                     
>                                                                               
>                                                                               
>                                     
>   *Measured* (TPC-DS 10 TB Parquet, 24 x r6id, same session, only the flag 
> changes)                                                                      
>                                        
>   ||Query||off (s)||on (s)||                                                  
>                                                                               
>                                     
>   |q65|148.9|70.3|                                                            
>                                                                               
>                                     
>   |q97|100.7|73.0|                                                            
>                                                                               
>                                     
>   |q78|259.3|232.4|          



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to