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

Denys Kuzmenko updated HIVE-30221:
----------------------------------
    Description: 
A vectorized ReduceSink serializes every row (BinarySortable key, LazyBinary 
value) and writes one Tez record per row. On TPC-DS q78 at 10 TB, 77% of LLAP 
CPU goes to the exchange           
  (ReduceSink 44%, Tez writer 33%). Trino spends 4-6% on the same rows: its 
PagePartitioner appends a page's rows to a page per partition and ships pages. 
On an unsorted edge the rows need no 
  key order, so they can travel the same way.                                   
                                                                                
                                
                                                                                
                                                                                
                                
  *Fix* ({{hive.vectorized.execution.columnar.shuffle.enabled}}, default false) 
                                                                                
                                
  * VectorReduceSinkColumnarOperator gathers the rows of each partition in 
column vectors and writes one record per block.                                 
                                     
  ** A block holds 32 MB / (partitions x row bytes) rows, kept within [64, 
1024].                                                                          
                                     
  ** A batch is appended in slices of a block's rows. Each slice takes two 
passes: slots per partition, then a typed scatter per column. Trino's row-wise 
append works the same way below 2 x   
  partitions rows per page.                                                     
                                                                                
                                
  * A row goes to the partition the row path gives it, computed by the row 
path's code.                                                                    
                                     
  ** The operator is a VectorReduceSinkUniformHashOperator and builds the key 
series of the ReduceSink it replaces.                                           
                                  
  ** A key gets the Murmur3 hash of its BinarySortable bytes, or the null key's 
hash when all its columns are null, modulo the edge's physical outputs.         
                                
  ** A block's HiveKey hash code is its partition, so a reducer's inputs 
partition alike whether they arrive columnar or not.                            
                                       
  * Block format: per column, a null flag per row and then the values.          
                                                                                
                                
  ** Supported values: long, double, timestamp and bytes.                       
                                                                                
                                
  ** A decimal travels as its scale plus the unscaled longs up to 18 digits, 
otherwise as BigInteger bytes, and can be read into either decimal vector.      
                                   
  * ReduceRecordSource decodes a block into the key and value columns of the 
reducer's batch. Bytes are referenced in place; a reducer that keeps its 
batches gets a copy.                      
  * Vectorizer, after a TezWork is vectorized, picks the qualifying edges.      
                                                                                
                                
  ** The edge must be a CUSTOM_SIMPLE_EDGE into the reducer's vectorized input: 
the big table of a dynamically partitioned hash join, or the input of an 
unsorted GROUP BY.                     
  ** Its ReduceSink must be uniform-hash, have no TopN, and carry only key and 
value column types a block supports (LONG, DOUBLE, BYTES, DECIMAL, DECIMAL_64, 
TIMESTAMP).                       
  ** The small table of a dynamically partitioned hash join keeps the row path, 
because its hash table loader reads serialized keys.  

*Measured*                                                                      
                                                                                
                              
  Cluster (TPC-DS 10 TB Parquet, 10 x r5d, same session, flag off vs on, the 44 
queries with a columnar edge, min of 3):                                        
                                
  * Total: 3,162.7 -> 2,885.4 s (-8.8%), with identical results.                
                                                                                
                                
  * Faster: q78 -103.4 s, q65 -51.7 s, q5 -36.8 s, q14 -31.7 s, q97 -30.8 s.    
                                                                                
                                
  * Slower: q75 +16.2 s, q64 +6.4 s.                                            
                                                                                
                                
  * On 24 x r6id: q78 -40.2 s, q65 -15.2 s, q95 -5.7 s.                         
                                                                                
                                
  These runs used an earlier revision that handled fixed-width keys only, 
before the key series. The other key types are not measured on the cluster yet. 
                                      
                                                                                
                                                                                
                                
  Microbenchmarks, ns per row. The figures leave out the per-record Tez write, 
which only the row path pays.                                                   
                                 
  ||Edge||Row path write||Columnar write||Row path read||Columnar read||        
                                                                                
                                
  |q78 value shape, 1,009 partitions|66-68|19-22, plus 34 for the key series 
hash|-|-|                                                                       
                                   
  |q11 year_total: 7 string keys and an int, a decimal value, 253 
partitions|214-258|364-424|180-185|13-19|                                       
                                              
  For string-heavy keys the write CPU is about even, because the columnar path 
serializes the keys for their hash and then copies them into the block.         
                                 


  Depends on HIVE-30223: its unsorted GROUP BY edge carries most of the 
measured gain, and columnar_shuffle.q turns it on. HIVE-30133 follows; it 
covers repeating partition columns and        
  empty-key ReduceSinks such as the Iceberg V3 DML delete edge.

> Vectorization: a ReduceSink of an unsorted edge ships its rows as columnar 
> blocks 
> ----------------------------------------------------------------------------------
>
>                 Key: HIVE-30221
>                 URL: https://issues.apache.org/jira/browse/HIVE-30221
>             Project: Hive
>          Issue Type: Improvement
>            Reporter: Denys Kuzmenko
>            Priority: Major
>
> A vectorized ReduceSink serializes every row (BinarySortable key, LazyBinary 
> value) and writes one Tez record per row. On TPC-DS q78 at 10 TB, 77% of LLAP 
> CPU goes to the exchange           
>   (ReduceSink 44%, Tez writer 33%). Trino spends 4-6% on the same rows: its 
> PagePartitioner appends a page's rows to a page per partition and ships 
> pages. On an unsorted edge the rows need no 
>   key order, so they can travel the same way.                                 
>                                                                               
>                                     
>                                                                               
>                                                                               
>                                     
>   *Fix* ({{hive.vectorized.execution.columnar.shuffle.enabled}}, default 
> false)                                                                        
>                                          
>   * VectorReduceSinkColumnarOperator gathers the rows of each partition in 
> column vectors and writes one record per block.                               
>                                        
>   ** A block holds 32 MB / (partitions x row bytes) rows, kept within [64, 
> 1024].                                                                        
>                                        
>   ** A batch is appended in slices of a block's rows. Each slice takes two 
> passes: slots per partition, then a typed scatter per column. Trino's 
> row-wise append works the same way below 2 x   
>   partitions rows per page.                                                   
>                                                                               
>                                     
>   * A row goes to the partition the row path gives it, computed by the row 
> path's code.                                                                  
>                                        
>   ** The operator is a VectorReduceSinkUniformHashOperator and builds the key 
> series of the ReduceSink it replaces.                                         
>                                     
>   ** A key gets the Murmur3 hash of its BinarySortable bytes, or the null 
> key's hash when all its columns are null, modulo the edge's physical outputs. 
>                                         
>   ** A block's HiveKey hash code is its partition, so a reducer's inputs 
> partition alike whether they arrive columnar or not.                          
>                                          
>   * Block format: per column, a null flag per row and then the values.        
>                                                                               
>                                     
>   ** Supported values: long, double, timestamp and bytes.                     
>                                                                               
>                                     
>   ** A decimal travels as its scale plus the unscaled longs up to 18 digits, 
> otherwise as BigInteger bytes, and can be read into either decimal vector.    
>                                      
>   * ReduceRecordSource decodes a block into the key and value columns of the 
> reducer's batch. Bytes are referenced in place; a reducer that keeps its 
> batches gets a copy.                      
>   * Vectorizer, after a TezWork is vectorized, picks the qualifying edges.    
>                                                                               
>                                     
>   ** The edge must be a CUSTOM_SIMPLE_EDGE into the reducer's vectorized 
> input: the big table of a dynamically partitioned hash join, or the input of 
> an unsorted GROUP BY.                     
>   ** Its ReduceSink must be uniform-hash, have no TopN, and carry only key 
> and value column types a block supports (LONG, DOUBLE, BYTES, DECIMAL, 
> DECIMAL_64, TIMESTAMP).                       
>   ** The small table of a dynamically partitioned hash join keeps the row 
> path, because its hash table loader reads serialized keys.  
> *Measured*                                                                    
>                                                                               
>                                   
>   Cluster (TPC-DS 10 TB Parquet, 10 x r5d, same session, flag off vs on, the 
> 44 queries with a columnar edge, min of 3):                                   
>                                      
>   * Total: 3,162.7 -> 2,885.4 s (-8.8%), with identical results.              
>                                                                               
>                                     
>   * Faster: q78 -103.4 s, q65 -51.7 s, q5 -36.8 s, q14 -31.7 s, q97 -30.8 s.  
>                                                                               
>                                     
>   * Slower: q75 +16.2 s, q64 +6.4 s.                                          
>                                                                               
>                                     
>   * On 24 x r6id: q78 -40.2 s, q65 -15.2 s, q95 -5.7 s.                       
>                                                                               
>                                     
>   These runs used an earlier revision that handled fixed-width keys only, 
> before the key series. The other key types are not measured on the cluster 
> yet.                                       
>                                                                               
>                                                                               
>                                     
>   Microbenchmarks, ns per row. The figures leave out the per-record Tez 
> write, which only the row path pays.                                          
>                                           
>   ||Edge||Row path write||Columnar write||Row path read||Columnar read||      
>                                                                               
>                                     
>   |q78 value shape, 1,009 partitions|66-68|19-22, plus 34 for the key series 
> hash|-|-|                                                                     
>                                      
>   |q11 year_total: 7 string keys and an int, a decimal value, 253 
> partitions|214-258|364-424|180-185|13-19|                                     
>                                                 
>   For string-heavy keys the write CPU is about even, because the columnar 
> path serializes the keys for their hash and then copies them into the block.  
>                                         
>   Depends on HIVE-30223: its unsorted GROUP BY edge carries most of the 
> measured gain, and columnar_shuffle.q turns it on. HIVE-30133 follows; it 
> covers repeating partition columns and        
>   empty-key ReduceSinks such as the Iceberg V3 DML delete edge.



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

Reply via email to