You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2018/11/19 17:27:33 UTC

[6/6] impala git commit: IMPALA-7367: Pack StringValue and CollectionValue slots

IMPALA-7367: Pack StringValue and CollectionValue slots

This change packs StringValue and CollectionValue slots to ensure
they now occupy 12 bytes instead of 16 bytes. This reduces the
memory requirements and improves the performance. Since Kudu
tuples are populated using a memcopy, 4 bytes of padding was
added to StringSlots in Kudu tables.

Testing:
Ran core tests.
Added static asserts to ensure the value sizes are as expected.
Performance tests on TPCH-40  produced 3.96% improvement.

Change-Id: I32f3b06622c087e4aa288e8db1bf4581b10d386a
Reviewed-on: http://gerrit.cloudera.org:8080/11599
Tested-by: Impala Public Jenkins <im...@cloudera.com>
Reviewed-by: Tim Armstrong <ta...@cloudera.com>


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/2a4835cf
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/2a4835cf
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/2a4835cf

Branch: refs/heads/master
Commit: 2a4835cfba7597362cc1e72e21315868c5c75d0a
Parents: 53ce6bb
Author: poojanilangekar <po...@cloudera.com>
Authored: Fri Nov 9 14:07:15 2018 -0800
Committer: Tim Armstrong <ta...@cloudera.com>
Committed: Mon Nov 19 17:27:13 2018 +0000

----------------------------------------------------------------------
 be/src/exec/text-converter.inline.h             |    6 +-
 be/src/exprs/expr-test.cc                       |   25 +-
 be/src/exprs/scalar-expr.cc                     |   24 -
 be/src/runtime/collection-value.h               |    2 +-
 be/src/runtime/descriptors.cc                   |    3 +-
 be/src/runtime/string-value.h                   |    2 +-
 be/src/runtime/types.h                          |    4 +-
 be/src/util/static-asserts.cc                   |    4 +-
 .../apache/impala/analysis/SlotDescriptor.java  |   10 +
 .../apache/impala/analysis/TupleDescriptor.java |   22 +-
 .../apache/impala/catalog/PrimitiveType.java    |    5 +-
 .../java/org/apache/impala/catalog/Type.java    |    4 +-
 .../apache/impala/analysis/AnalyzerTest.java    |   50 +-
 .../queries/PlannerTest/constant-folding.test   |   30 +-
 .../PlannerTest/fk-pk-join-detection.test       |   34 +-
 .../queries/PlannerTest/join-order.test         |   26 +-
 .../queries/PlannerTest/max-row-size.test       |  148 +-
 .../queries/PlannerTest/mt-dop-validation.test  |  100 +-
 .../PlannerTest/parquet-filtering-disabled.test |   72 +-
 .../queries/PlannerTest/parquet-filtering.test  |  132 +-
 .../queries/PlannerTest/partition-pruning.test  |    2 +-
 .../PlannerTest/resource-requirements.test      | 1376 +++++++++---------
 .../PlannerTest/sort-expr-materialization.test  |   34 +-
 .../PlannerTest/spillable-buffer-sizing.test    |  406 +++---
 .../queries/PlannerTest/subquery-rewrite.test   |   16 +-
 .../queries/PlannerTest/tablesample.test        |   18 +-
 .../queries/PlannerTest/tpcds-all.test          |   98 +-
 .../queries/PlannerTest/tpch-all.test           |   78 +-
 .../queries/PlannerTest/tpch-kudu.test          |    8 +-
 .../queries/PlannerTest/tpch-nested.test        |  166 +--
 .../queries/QueryTest/explain-level2.test       |   10 +-
 .../queries/QueryTest/explain-level3.test       |   10 +-
 .../QueryTest/spilling-no-debug-action.test     |    2 +-
 33 files changed, 1459 insertions(+), 1468 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/exec/text-converter.inline.h
----------------------------------------------------------------------
diff --git a/be/src/exec/text-converter.inline.h b/be/src/exec/text-converter.inline.h
index c56bcce..4fe0e54 100644
--- a/be/src/exec/text-converter.inline.h
+++ b/be/src/exec/text-converter.inline.h
@@ -83,7 +83,11 @@ inline bool TextConverter::WriteSlot(const SlotDescriptor* slot_desc, Tuple* tup
             reinterpret_cast<char*>(slot);
         if (UNLIKELY(str.ptr == NULL)) return false;
         if (need_escape) {
-          UnescapeString(data, str.ptr, &str.len, buffer_len);
+          // Use a temporary variable on the stack to avoid accessing an unaligned
+          // pointer.
+          int str_len = str.len;
+          UnescapeString(data, str.ptr, &str_len, buffer_len);
+          str.len = str_len;
         } else {
           memcpy(str.ptr, data, str.len);
         }

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/exprs/expr-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc
index bab16ca..cbf9044 100644
--- a/be/src/exprs/expr-test.cc
+++ b/be/src/exprs/expr-test.cc
@@ -7596,7 +7596,7 @@ TEST_F(ExprTest, ResultsLayoutTest) {
       exprs.push_back(CreateLiteral(t, "2016-11-09"));
     }
     if (t.IsVarLenStringType()) {
-      ValidateLayout(exprs, 16, 0, expected_offsets);
+      ValidateLayout(exprs, 12, 0, expected_offsets);
     } else {
       ValidateLayout(exprs, t.GetByteSize(), -1, expected_offsets);
     }
@@ -7607,7 +7607,8 @@ TEST_F(ExprTest, ResultsLayoutTest) {
   expected_offsets.clear();
   exprs.clear();
 
-  // Test layout adding a bunch of exprs.  This is designed to trigger padding.
+  // Test layout adding a bunch of exprs.  Previously, this triggered padding.
+  // IMPALA-7367 removed the alignment requirement, hence the values are not padded.
   // The expected result is computed along the way
   exprs.push_back(CreateLiteral(TYPE_BOOLEAN, "0"));
   exprs.push_back(CreateLiteral(TYPE_TINYINT, "0"));
@@ -7615,7 +7616,7 @@ TEST_F(ExprTest, ResultsLayoutTest) {
   expected_offsets[1].insert(expected_byte_size);
   expected_offsets[1].insert(expected_byte_size + 1);
   expected_offsets[1].insert(expected_byte_size + 2);
-  expected_byte_size += 3 * 1 + 1;  // 1 byte of padding
+  expected_byte_size += 3 * 1;
 
   exprs.push_back(CreateLiteral(TYPE_SMALLINT, "0"));
   expected_offsets[2].insert(expected_byte_size);
@@ -7623,9 +7624,7 @@ TEST_F(ExprTest, ResultsLayoutTest) {
 
   exprs.push_back(CreateLiteral(ColumnType::CreateCharType(3), "0"));
   expected_offsets[3].insert(expected_byte_size);
-  expected_byte_size += 3 + 3; // 3 byte of padding
-  ASSERT_EQ(expected_byte_size % 4, 0);
-
+  expected_byte_size += 3;
   exprs.push_back(CreateLiteral(TYPE_INT, "0"));
   exprs.push_back(CreateLiteral(TYPE_FLOAT, "0"));
   exprs.push_back(CreateLiteral(TYPE_FLOAT, "0"));
@@ -7634,8 +7633,7 @@ TEST_F(ExprTest, ResultsLayoutTest) {
   expected_offsets[4].insert(expected_byte_size + 4);
   expected_offsets[4].insert(expected_byte_size + 8);
   expected_offsets[4].insert(expected_byte_size + 12);
-  expected_byte_size += 4 * 4 + 4;  // 4 bytes of padding
-  ASSERT_EQ(expected_byte_size % 8, 0);
+  expected_byte_size += 4 * 4;
 
   exprs.push_back(CreateLiteral(TYPE_BIGINT, "0"));
   exprs.push_back(CreateLiteral(TYPE_BIGINT, "0"));
@@ -7647,8 +7645,7 @@ TEST_F(ExprTest, ResultsLayoutTest) {
   expected_offsets[8].insert(expected_byte_size + 16);
   expected_offsets[8].insert(expected_byte_size + 24);
   expected_offsets[8].insert(expected_byte_size + 32);
-  expected_byte_size += 5 * 8;      // No more padding
-  ASSERT_EQ(expected_byte_size % 8, 0);
+  expected_byte_size += 5 * 8;
 
   exprs.push_back(CreateLiteral(TYPE_TIMESTAMP, "2016-11-09"));
   exprs.push_back(CreateLiteral(TYPE_TIMESTAMP, "2016-11-09"));
@@ -7657,17 +7654,15 @@ TEST_F(ExprTest, ResultsLayoutTest) {
   expected_offsets[16].insert(expected_byte_size + 16);
   expected_offsets[16].insert(expected_byte_size + 32);
   expected_byte_size += 3 * 16;
-  ASSERT_EQ(expected_byte_size % 8, 0);
 
   exprs.push_back(CreateLiteral(TYPE_STRING, "0"));
   exprs.push_back(CreateLiteral(TYPE_STRING, "0"));
   exprs.push_back(CreateLiteral(ColumnType::CreateVarcharType(1), "0"));
   expected_offsets[0].insert(expected_byte_size);
-  expected_offsets[0].insert(expected_byte_size + 16);
-  expected_offsets[0].insert(expected_byte_size + 32);
+  expected_offsets[0].insert(expected_byte_size + 12);
+  expected_offsets[0].insert(expected_byte_size + 24);
   expected_var_begin = expected_byte_size;
-  expected_byte_size += 3 * 16;
-  ASSERT_EQ(expected_byte_size % 8, 0);
+  expected_byte_size += 3 * 12;
 
   // Validate computed layout
   ValidateLayout(exprs, expected_byte_size, expected_var_begin, expected_offsets);

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/exprs/scalar-expr.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/scalar-expr.cc b/be/src/exprs/scalar-expr.cc
index 00e6709..e69146b 100644
--- a/be/src/exprs/scalar-expr.cc
+++ b/be/src/exprs/scalar-expr.cc
@@ -225,8 +225,6 @@ struct MemLayoutData {
   bool variable_length;
   int alignment;
 
-  // TODO: sort by type as well?  Any reason to do this?
-  // TODO: would sorting in reverse order of size be faster due to better packing?
   // TODO: why put var-len at end?
   bool operator<(const MemLayoutData& rhs) const {
     // variable_len go at end
@@ -243,10 +241,6 @@ int ScalarExpr::ComputeResultsLayout(const vector<ScalarExpr*>& exprs,
     return 0;
   }
 
-  // Don't align more than word (8-byte) size. There's no performance gain beyond 8-byte
-  // alignment, and there is a performance gain to keeping the results buffer small. This
-  // is consistent with what compilers do.
-  int MAX_ALIGNMENT = sizeof(int64_t);
 
   vector<MemLayoutData> data;
   data.resize(exprs.size());
@@ -259,33 +253,15 @@ int ScalarExpr::ComputeResultsLayout(const vector<ScalarExpr*>& exprs,
     DCHECK_GT(data[i].byte_size, 0);
     data[i].variable_length = exprs[i]->type().IsVarLenStringType();
 
-    bool fixed_len_char = exprs[i]->type().type == TYPE_CHAR && !data[i].variable_length;
-
-    // Compute the alignment of this value. Values should be self-aligned for optimal
-    // memory access speed, up to the max alignment (e.g., if this value is an int32_t,
-    // its offset in the buffer should be divisible by sizeof(int32_t)).
-    // TODO: is self-alignment really necessary for perf?
-    if (!fixed_len_char) {
-      data[i].alignment = min(data[i].byte_size, MAX_ALIGNMENT);
-    } else {
-      // Fixed-len chars are aligned to a one-byte boundary, as if they were char[],
-      // leaving no padding between them and the previous value.
-      data[i].alignment = 1;
-    }
   }
 
   sort(data.begin(), data.end());
 
-  // Walk the types and store in a packed aligned layout
   int byte_offset = 0;
-
   offsets->resize(exprs.size());
   *var_result_begin = -1;
 
   for (int i = 0; i < data.size(); ++i) {
-    // Increase byte_offset so data[i] is at the right alignment (i.e. add padding between
-    // this value and the previous).
-    byte_offset = BitUtil::RoundUp(byte_offset, data[i].alignment);
 
     (*offsets)[data[i].expr_idx] = byte_offset;
     if (data[i].variable_length && *var_result_begin == -1) {

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/runtime/collection-value.h
----------------------------------------------------------------------
diff --git a/be/src/runtime/collection-value.h b/be/src/runtime/collection-value.h
index 29ecb17..a71eff8 100644
--- a/be/src/runtime/collection-value.h
+++ b/be/src/runtime/collection-value.h
@@ -27,7 +27,7 @@ namespace impala {
 /// arrays and maps are effectively indistinguishable; a map can be thought of as an array
 /// of key/value structs (and neither of these fields are necessarily materialized in the
 /// item tuples).
-struct CollectionValue {
+struct __attribute__((__packed__)) CollectionValue {
   /// Pointer to buffer containing item tuples.
   uint8_t* ptr;
 

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/runtime/descriptors.cc
----------------------------------------------------------------------
diff --git a/be/src/runtime/descriptors.cc b/be/src/runtime/descriptors.cc
index 12de054..068274a 100644
--- a/be/src/runtime/descriptors.cc
+++ b/be/src/runtime/descriptors.cc
@@ -742,7 +742,8 @@ llvm::StructType* TupleDescriptor::GetLlvmStruct(LlvmCodeGen* codegen) const {
   for (SlotDescriptor* slot: slots()) {
     // Verify that the byte offset in the llvm struct matches the tuple offset
     // computed in the FE.
-    DCHECK_EQ(layout->getElementOffset(slot->llvm_field_idx()), slot->tuple_offset());
+    DCHECK_EQ(layout->getElementOffset(slot->llvm_field_idx()), slot->tuple_offset())
+        << id_;
   }
   return tuple_struct;
 }

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/runtime/string-value.h
----------------------------------------------------------------------
diff --git a/be/src/runtime/string-value.h b/be/src/runtime/string-value.h
index 5b7a7e4..e0e624b 100644
--- a/be/src/runtime/string-value.h
+++ b/be/src/runtime/string-value.h
@@ -33,7 +33,7 @@ namespace impala {
 /// The returned StringValue of all functions that return StringValue
 /// shares its buffer with the parent.
 /// TODO: rename this to be less confusing with impala_udf::StringVal.
-struct StringValue {
+struct __attribute__((__packed__)) StringValue {
   /// The current limitation for a string instance is 1GB character data.
   /// See IMPALA-1619 for more details.
   static const int MAX_LENGTH = (1 << 30);

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/runtime/types.h
----------------------------------------------------------------------
diff --git a/be/src/runtime/types.h b/be/src/runtime/types.h
index 1509c1f..af4f9a9 100644
--- a/be/src/runtime/types.h
+++ b/be/src/runtime/types.h
@@ -260,13 +260,13 @@ struct ColumnType {
     switch (type) {
       case TYPE_STRING:
       case TYPE_VARCHAR:
-        return 16;
+        return 12;
       case TYPE_CHAR:
       case TYPE_FIXED_UDA_INTERMEDIATE:
         return len;
       case TYPE_ARRAY:
       case TYPE_MAP:
-        return 16;
+        return 12;
       case TYPE_STRUCT:
         DCHECK(false) << "TYPE_STRUCT slot not possible";
       default:

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/be/src/util/static-asserts.cc
----------------------------------------------------------------------
diff --git a/be/src/util/static-asserts.cc b/be/src/util/static-asserts.cc
index 7662906..0680c73 100644
--- a/be/src/util/static-asserts.cc
+++ b/be/src/util/static-asserts.cc
@@ -18,6 +18,7 @@
 #include <boost/static_assert.hpp>
 
 #include "common/hdfs.h"
+#include "runtime/collection-value.h"
 #include "runtime/string-value.h"
 #include "runtime/timestamp-value.h"
 #include "udf/udf.h"
@@ -28,12 +29,13 @@ namespace impala {
 // at compile time.  If these asserts fail, the compile will fail.
 class UnusedClass {
  private:
-  BOOST_STATIC_ASSERT(sizeof(StringValue) == 16);
+  BOOST_STATIC_ASSERT(sizeof(StringValue) == 12);
   BOOST_STATIC_ASSERT(offsetof(StringValue, len) == 8);
   BOOST_STATIC_ASSERT(sizeof(TimestampValue) == 16);
   BOOST_STATIC_ASSERT(offsetof(TimestampValue, date_) == 8);
   BOOST_STATIC_ASSERT(sizeof(boost::posix_time::time_duration) == 8);
   BOOST_STATIC_ASSERT(sizeof(boost::gregorian::date) == 4);
+  BOOST_STATIC_ASSERT(sizeof(CollectionValue) == 12);
   BOOST_STATIC_ASSERT(sizeof(hdfsFS) == sizeof(void*));
   BOOST_STATIC_ASSERT(sizeof(hdfsFile) == sizeof(void*));
 

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/fe/src/main/java/org/apache/impala/analysis/SlotDescriptor.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/SlotDescriptor.java b/fe/src/main/java/org/apache/impala/analysis/SlotDescriptor.java
index aae3863..aae3efa 100644
--- a/fe/src/main/java/org/apache/impala/analysis/SlotDescriptor.java
+++ b/fe/src/main/java/org/apache/impala/analysis/SlotDescriptor.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.impala.catalog.Column;
 import org.apache.impala.catalog.ColumnStats;
+import org.apache.impala.catalog.FeKuduTable;
 import org.apache.impala.catalog.KuduColumn;
 import org.apache.impala.catalog.Type;
 import org.apache.impala.thrift.TSlotDescriptor;
@@ -182,6 +183,15 @@ public class SlotDescriptor {
   }
 
   /**
+   * Returns true if this slot is of STRING type in a kudu table.
+   */
+  public boolean isKuduStringSlot() {
+    if (getParent() == null) return false;
+    if (!(getParent().getTable() instanceof FeKuduTable)) return false;
+    return getType().isStringType();
+  }
+
+  /**
    * Assembles the absolute materialized path to this slot starting from the schema
    * root. The materialized path points to the first non-struct schema element along the
    * path starting from the parent's tuple path to this slot's path.

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/fe/src/main/java/org/apache/impala/analysis/TupleDescriptor.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/TupleDescriptor.java b/fe/src/main/java/org/apache/impala/analysis/TupleDescriptor.java
index bf2d310..98621ef 100644
--- a/fe/src/main/java/org/apache/impala/analysis/TupleDescriptor.java
+++ b/fe/src/main/java/org/apache/impala/analysis/TupleDescriptor.java
@@ -70,9 +70,12 @@ import com.google.common.collect.Lists;
  *
  * Example: select bool_col, int_col, string_col, smallint_col from functional.alltypes
  * Slots:   string_col|int_col|smallint_col|bool_col|null_byte
- * Offsets: 0          16      20           22       23
+ * Offsets: 0          12      16           18       19
  */
 public class TupleDescriptor {
+  // Padding size in bytes for Kudu string slots.
+  private static final int KUDU_STRING_PADDING = 4;
+
   private final TupleId id_;
   private final String debugName_;  // debug-only
   private final ArrayList<SlotDescriptor> slots_ = Lists.newArrayList();
@@ -261,17 +264,24 @@ public class TupleDescriptor {
     for (SlotDescriptor d: slots_) {
       if (!d.isMaterialized()) continue;
       ColumnStats stats = d.getStats();
+      int slotSize = d.getType().getSlotSize();
+
       if (stats.hasAvgSerializedSize()) {
         avgSerializedSize_ += d.getStats().getAvgSerializedSize();
       } else {
         // TODO: for computed slots, try to come up with stats estimates
-        avgSerializedSize_ += d.getType().getSlotSize();
+        avgSerializedSize_ += slotSize;
+      }
+      // Add padding for a KUDU string slot.
+      if (d.isKuduStringSlot()) {
+        slotSize += KUDU_STRING_PADDING;
+        avgSerializedSize_ += KUDU_STRING_PADDING;
       }
-      if (!slotsBySize.containsKey(d.getType().getSlotSize())) {
-        slotsBySize.put(d.getType().getSlotSize(), new ArrayList<SlotDescriptor>());
+      if (!slotsBySize.containsKey(slotSize)) {
+        slotsBySize.put(slotSize, new ArrayList<SlotDescriptor>());
       }
-      totalSlotSize += d.getType().getSlotSize();
-      slotsBySize.get(d.getType().getSlotSize()).add(d);
+      totalSlotSize += slotSize;
+      slotsBySize.get(slotSize).add(d);
       if (d.getIsNullable() || alwaysAddNullBit) ++numNullBits;
     }
     // we shouldn't have anything of size <= 0

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/fe/src/main/java/org/apache/impala/catalog/PrimitiveType.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/PrimitiveType.java b/fe/src/main/java/org/apache/impala/catalog/PrimitiveType.java
index e09fd7b..45cfe12 100644
--- a/fe/src/main/java/org/apache/impala/catalog/PrimitiveType.java
+++ b/fe/src/main/java/org/apache/impala/catalog/PrimitiveType.java
@@ -39,9 +39,8 @@ public enum PrimitiveType {
   // The timestamp structure is 12 bytes, Aligning to 8 bytes makes it 16.
   TIMESTAMP("TIMESTAMP", 16, TPrimitiveType.TIMESTAMP),
   // 8-byte pointer and 4-byte length indicator (12 bytes total).
-  // Aligning to 8 bytes so 16 total.
-  STRING("STRING", 16, TPrimitiveType.STRING),
-  VARCHAR("VARCHAR", 16, TPrimitiveType.VARCHAR),
+  STRING("STRING", 12, TPrimitiveType.STRING),
+  VARCHAR("VARCHAR", 12, TPrimitiveType.VARCHAR),
 
   // Unsupported scalar type.
   BINARY("BINARY", -1, TPrimitiveType.BINARY),

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/fe/src/main/java/org/apache/impala/catalog/Type.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/Type.java b/fe/src/main/java/org/apache/impala/catalog/Type.java
index 664fca1..d20090a 100644
--- a/fe/src/main/java/org/apache/impala/catalog/Type.java
+++ b/fe/src/main/java/org/apache/impala/catalog/Type.java
@@ -224,9 +224,7 @@ public abstract class Type {
    */
   public int getSlotSize() {
     // 8-byte pointer and 4-byte length indicator (12 bytes total).
-    // Per struct alignment rules, there is an extra 4 bytes of padding to align to 8
-    // bytes so 16 bytes total.
-    if (isCollectionType()) return 16;
+    if (isCollectionType()) return 12;
     throw new IllegalStateException("getSlotSize() not implemented for type " + toSql());
   }
 

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/fe/src/test/java/org/apache/impala/analysis/AnalyzerTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzerTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzerTest.java
index 643f85e..e83202e 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzerTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzerTest.java
@@ -116,20 +116,20 @@ public class AnalyzerTest extends FrontendTestBase {
     tupleDesc.materializeSlots();
     descTbl.computeMemLayout();
 
-    Assert.assertEquals(97.0f, tupleDesc.getAvgSerializedSize(), 0.0);
-    checkLayoutParams("functional.alltypes.date_string_col", 16, 0, 88, 0, analyzer);
-    checkLayoutParams("functional.alltypes.string_col", 16, 16, 88, 1, analyzer);
-    checkLayoutParams("functional.alltypes.timestamp_col", 16, 32, 88, 2, analyzer);
-    checkLayoutParams("functional.alltypes.bigint_col", 8, 48, 88, 3, analyzer);
-    checkLayoutParams("functional.alltypes.double_col", 8, 56, 88, 4, analyzer);
-    checkLayoutParams("functional.alltypes.id", 4, 64, 88, 5, analyzer);
-    checkLayoutParams("functional.alltypes.int_col", 4, 68, 88, 6, analyzer);
-    checkLayoutParams("functional.alltypes.float_col", 4, 72, 88, 7, analyzer);
-    checkLayoutParams("functional.alltypes.year", 4, 76, 89, 0, analyzer);
-    checkLayoutParams("functional.alltypes.month", 4, 80, 89, 1, analyzer);
-    checkLayoutParams("functional.alltypes.smallint_col", 2, 84, 89, 2, analyzer);
-    checkLayoutParams("functional.alltypes.bool_col", 1, 86, 89, 3, analyzer);
-    checkLayoutParams("functional.alltypes.tinyint_col", 1, 87, 89, 4, analyzer);
+    Assert.assertEquals(89.0f, tupleDesc.getAvgSerializedSize(), 0.0);
+    checkLayoutParams("functional.alltypes.timestamp_col", 16, 0, 80, 0, analyzer);
+    checkLayoutParams("functional.alltypes.date_string_col", 12, 16, 80, 1, analyzer);
+    checkLayoutParams("functional.alltypes.string_col", 12, 28, 80, 2, analyzer);
+    checkLayoutParams("functional.alltypes.bigint_col", 8, 40, 80, 3, analyzer);
+    checkLayoutParams("functional.alltypes.double_col", 8, 48, 80, 4, analyzer);
+    checkLayoutParams("functional.alltypes.id", 4, 56, 80, 5, analyzer);
+    checkLayoutParams("functional.alltypes.int_col", 4, 60, 80, 6, analyzer);
+    checkLayoutParams("functional.alltypes.float_col", 4, 64, 80, 7, analyzer);
+    checkLayoutParams("functional.alltypes.year", 4, 68, 81, 0, analyzer);
+    checkLayoutParams("functional.alltypes.month", 4, 72, 81, 1, analyzer);
+    checkLayoutParams("functional.alltypes.smallint_col", 2, 76, 81, 2, analyzer);
+    checkLayoutParams("functional.alltypes.bool_col", 1, 78, 81, 3, analyzer);
+    checkLayoutParams("functional.alltypes.tinyint_col", 1, 79, 81, 4, analyzer);
   }
 
   private void testNonNullable() throws AnalysisException {
@@ -183,22 +183,22 @@ public class AnalyzerTest extends FrontendTestBase {
     slots.get(9).setIsMaterialized(false);
     descTbl.computeMemLayout();
 
-    Assert.assertEquals(68.0f, tupleDesc.getAvgSerializedSize(), 0.0);
+    Assert.assertEquals(64.0f, tupleDesc.getAvgSerializedSize(), 0.0);
     // Check non-materialized slots.
     checkLayoutParams("functional.alltypes.id", 0, -1, 0, 0, analyzer);
     checkLayoutParams("functional.alltypes.double_col", 0, -1, 0, 0, analyzer);
     checkLayoutParams("functional.alltypes.string_col", 0, -1, 0, 0, analyzer);
     // Check materialized slots.
-    checkLayoutParams("functional.alltypes.date_string_col", 16, 0, 60, 0, analyzer);
-    checkLayoutParams("functional.alltypes.timestamp_col", 16, 16, 60, 1, analyzer);
-    checkLayoutParams("functional.alltypes.bigint_col", 8, 32, 60, 2, analyzer);
-    checkLayoutParams("functional.alltypes.int_col", 4, 40, 60, 3, analyzer);
-    checkLayoutParams("functional.alltypes.float_col", 4, 44, 60, 4, analyzer);
-    checkLayoutParams("functional.alltypes.year", 4, 48, 60, 5, analyzer);
-    checkLayoutParams("functional.alltypes.month", 4, 52, 60, 6, analyzer);
-    checkLayoutParams("functional.alltypes.smallint_col", 2, 56, 60, 7, analyzer);
-    checkLayoutParams("functional.alltypes.bool_col", 1, 58, 61, 0, analyzer);
-    checkLayoutParams("functional.alltypes.tinyint_col", 1, 59, 61, 1, analyzer);
+    checkLayoutParams("functional.alltypes.timestamp_col", 16, 0, 56, 0, analyzer);
+    checkLayoutParams("functional.alltypes.date_string_col", 12, 16, 56, 1, analyzer);
+    checkLayoutParams("functional.alltypes.bigint_col", 8, 28, 56, 2, analyzer);
+    checkLayoutParams("functional.alltypes.int_col", 4, 36, 56, 3, analyzer);
+    checkLayoutParams("functional.alltypes.float_col", 4, 40, 56, 4, analyzer);
+    checkLayoutParams("functional.alltypes.year", 4, 44, 56, 5, analyzer);
+    checkLayoutParams("functional.alltypes.month", 4, 48, 56, 6, analyzer);
+    checkLayoutParams("functional.alltypes.smallint_col", 2, 52, 56, 7, analyzer);
+    checkLayoutParams("functional.alltypes.bool_col", 1, 54, 57, 0, analyzer);
+    checkLayoutParams("functional.alltypes.tinyint_col", 1, 55, 57, 1, analyzer);
   }
 
   private void checkLayoutParams(SlotDescriptor d, int byteSize, int byteOffset,

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/testdata/workloads/functional-planner/queries/PlannerTest/constant-folding.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/constant-folding.test b/testdata/workloads/functional-planner/queries/PlannerTest/constant-folding.test
index 88d23d4..5b1cbe4 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/constant-folding.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/constant-folding.test
@@ -15,34 +15,34 @@ PLAN-ROOT SINK
 |
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=2,1,0 row-size=52B cardinality=1500000
+|  tuple-ids=2,1,0 row-size=44B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 |--08:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=24B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1,0 row-size=52B cardinality=100
+|  |  mem-estimate=20B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=2,1,0 row-size=44B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=24B cardinality=1
+|  |     tuple-ids=0 row-size=20B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  04:SUBPLAN
 |  |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1 row-size=28B cardinality=100
+|  |  tuple-ids=2,1 row-size=24B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--07:NESTED LOOP JOIN [CROSS JOIN]
-|  |  |  mem-estimate=24B mem-reservation=0B thread-reservation=0
-|  |  |  tuple-ids=2,1 row-size=28B cardinality=10
+|  |  |  mem-estimate=20B mem-reservation=0B thread-reservation=0
+|  |  |  tuple-ids=2,1 row-size=24B cardinality=10
 |  |  |  in pipelines: 00(GETNEXT)
 |  |  |
 |  |  |--05:SINGULAR ROW SRC
 |  |  |     parent-subplan=04
 |  |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  |     tuple-ids=1 row-size=24B cardinality=1
+|  |  |     tuple-ids=1 row-size=20B cardinality=1
 |  |  |     in pipelines: 00(GETNEXT)
 |  |  |
 |  |  06:UNNEST [o.o_lineitems]
@@ -63,7 +63,7 @@ PLAN-ROOT SINK
    predicates on o: !empty(o.o_lineitems), o_orderkey = CAST(4 AS BIGINT)
    predicates on o_lineitems: CAST(20 AS BIGINT) + CAST(l_linenumber AS BIGINT) < CAST(0 AS BIGINT)
    stored statistics:
-     table: rows=150000 size=289.00MB
+     table: rows=150000 size=288.96MB
      columns missing stats: c_orders
    extrapolated-rows=disabled max-scan-range-rows=44227
    parquet statistics predicates: c_custkey > CAST(10 AS BIGINT)
@@ -72,7 +72,7 @@ PLAN-ROOT SINK
    parquet dictionary predicates on o: o_orderkey = CAST(4 AS BIGINT)
    parquet dictionary predicates on o_lineitems: CAST(20 AS BIGINT) + CAST(l_linenumber AS BIGINT) < CAST(0 AS BIGINT)
    mem-estimate=264.00MB mem-reservation=16.00MB thread-reservation=1
-   tuple-ids=0 row-size=24B cardinality=15000
+   tuple-ids=0 row-size=20B cardinality=15000
    in pipelines: 00(GETNEXT)
 ====
 # Test HBase scan node.
@@ -96,7 +96,7 @@ PLAN-ROOT SINK
      table: rows=10000
      columns: all
    mem-estimate=4.00KB mem-reservation=0B thread-reservation=0
-   tuple-ids=0 row-size=119B cardinality=1
+   tuple-ids=0 row-size=107B cardinality=1
    in pipelines: 00(GETNEXT)
 ====
 # Test datasource scan node.
@@ -115,7 +115,7 @@ PLAN-ROOT SINK
 data source predicates: CAST(tinyint_col AS DOUBLE) < CAST(256 AS DOUBLE), int_col < CAST(2 AS INT)
 predicates: float_col != CAST(0 AS FLOAT)
    mem-estimate=1.00GB mem-reservation=0B thread-reservation=0
-   tuple-ids=0 row-size=116B cardinality=500
+   tuple-ids=0 row-size=112B cardinality=500
    in pipelines: 00(GETNEXT)
 ====
 # Test aggregation.
@@ -354,14 +354,14 @@ PLAN-ROOT SINK
 |  order by: greatest(20, bigint_col) ASC
 |  window: ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
 |  mem-estimate=4.00MB mem-reservation=4.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=3,2 row-size=61B cardinality=7300
+|  tuple-ids=3,2 row-size=53B cardinality=7300
 |  in pipelines: 01(GETNEXT)
 |
 01:SORT
 |  order by: concat('ab', string_col) ASC NULLS FIRST, greatest(20, bigint_col) ASC
 |  materialized: concat('ab', string_col), greatest(20, bigint_col)
 |  mem-estimate=12.00MB mem-reservation=12.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=3 row-size=53B cardinality=7300
+|  tuple-ids=3 row-size=45B cardinality=7300
 |  in pipelines: 01(GETNEXT), 00(OPEN)
 |
 00:SCAN HDFS [functional.alltypes]
@@ -372,7 +372,7 @@ PLAN-ROOT SINK
      columns: all
    extrapolated-rows=disabled max-scan-range-rows=310
    mem-estimate=128.00MB mem-reservation=32.00KB thread-reservation=1
-   tuple-ids=0 row-size=29B cardinality=7300
+   tuple-ids=0 row-size=25B cardinality=7300
    in pipelines: 00(GETNEXT)
 ====
 # Test sort node.

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/testdata/workloads/functional-planner/queries/PlannerTest/fk-pk-join-detection.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/fk-pk-join-detection.test b/testdata/workloads/functional-planner/queries/PlannerTest/fk-pk-join-detection.test
index 881f2da..8b71f11 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/fk-pk-join-detection.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/fk-pk-join-detection.test
@@ -5,7 +5,7 @@ on ss_customer_sk = c_customer_sk
 where c_salutation = 'Mrs.'
 ---- PLAN
 F00:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=185.50MB mem-reservation=25.50MB thread-reservation=3 runtime-filters-memory=1.00MB
+|  Per-Host Resources: mem-estimate=181.75MB mem-reservation=21.75MB thread-reservation=3 runtime-filters-memory=1.00MB
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
@@ -13,8 +13,8 @@ PLAN-ROOT SINK
 |  hash predicates: ss_customer_sk = c_customer_sk
 |  fk/pk conjuncts: ss_customer_sk = c_customer_sk
 |  runtime filters: RF000[bloom] <- c_customer_sk
-|  mem-estimate=8.50MB mem-reservation=8.50MB spill-buffer=512.00KB thread-reservation=0
-|  tuple-ids=0,1 row-size=355B cardinality=529700
+|  mem-estimate=4.75MB mem-reservation=4.75MB spill-buffer=256.00KB thread-reservation=0
+|  tuple-ids=0,1 row-size=319B cardinality=529700
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--01:SCAN HDFS [tpcds.customer]
@@ -25,7 +25,7 @@ PLAN-ROOT SINK
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=100000
 |     mem-estimate=48.00MB mem-reservation=8.00MB thread-reservation=1
-|     tuple-ids=1 row-size=255B cardinality=16667
+|     tuple-ids=1 row-size=219B cardinality=16667
 |     in pipelines: 01(GETNEXT)
 |
 00:SCAN HDFS [tpcds.store_sales]
@@ -48,7 +48,7 @@ on ss_customer_sk = c_customer_sk
 where c_salutation = 'Mrs.'
 ---- PLAN
 F00:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=184.50MB mem-reservation=24.50MB thread-reservation=3
+|  Per-Host Resources: mem-estimate=180.75MB mem-reservation=20.75MB thread-reservation=3
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
@@ -56,8 +56,8 @@ PLAN-ROOT SINK
 |  hash predicates: ss_customer_sk = c_customer_sk
 |  fk/pk conjuncts: ss_customer_sk = c_customer_sk
 |  other predicates: c_salutation = 'Mrs.'
-|  mem-estimate=8.50MB mem-reservation=8.50MB spill-buffer=512.00KB thread-reservation=0
-|  tuple-ids=0,1N row-size=355B cardinality=2880404
+|  mem-estimate=4.75MB mem-reservation=4.75MB spill-buffer=256.00KB thread-reservation=0
+|  tuple-ids=0,1N row-size=319B cardinality=2880404
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--01:SCAN HDFS [tpcds.customer]
@@ -68,7 +68,7 @@ PLAN-ROOT SINK
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=100000
 |     mem-estimate=48.00MB mem-reservation=8.00MB thread-reservation=1
-|     tuple-ids=1 row-size=255B cardinality=16667
+|     tuple-ids=1 row-size=219B cardinality=16667
 |     in pipelines: 01(GETNEXT)
 |
 00:SCAN HDFS [tpcds.store_sales]
@@ -90,7 +90,7 @@ on ss_customer_sk = c_customer_sk
 where c_salutation = 'Mrs.'
 ---- PLAN
 F00:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=185.50MB mem-reservation=25.50MB thread-reservation=3 runtime-filters-memory=1.00MB
+|  Per-Host Resources: mem-estimate=181.75MB mem-reservation=21.75MB thread-reservation=3 runtime-filters-memory=1.00MB
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
@@ -98,8 +98,8 @@ PLAN-ROOT SINK
 |  hash predicates: ss_customer_sk = c_customer_sk
 |  fk/pk conjuncts: ss_customer_sk = c_customer_sk
 |  runtime filters: RF000[bloom] <- c_customer_sk
-|  mem-estimate=8.50MB mem-reservation=8.50MB spill-buffer=512.00KB thread-reservation=0
-|  tuple-ids=0N,1 row-size=355B cardinality=529700
+|  mem-estimate=4.75MB mem-reservation=4.75MB spill-buffer=256.00KB thread-reservation=0
+|  tuple-ids=0N,1 row-size=319B cardinality=529700
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--01:SCAN HDFS [tpcds.customer]
@@ -110,7 +110,7 @@ PLAN-ROOT SINK
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=100000
 |     mem-estimate=48.00MB mem-reservation=8.00MB thread-reservation=1
-|     tuple-ids=1 row-size=255B cardinality=16667
+|     tuple-ids=1 row-size=219B cardinality=16667
 |     in pipelines: 01(GETNEXT)
 |
 00:SCAN HDFS [tpcds.store_sales]
@@ -223,7 +223,7 @@ PLAN-ROOT SINK
 |  fk/pk conjuncts: b.d_date_sk = a.d_date_sk
 |  runtime filters: RF000[bloom] <- a.d_date_sk
 |  mem-estimate=17.00MB mem-reservation=17.00MB spill-buffer=1.00MB thread-reservation=0
-|  tuple-ids=1,0 row-size=606B cardinality=36525
+|  tuple-ids=1,0 row-size=510B cardinality=36525
 |  in pipelines: 01(GETNEXT), 00(OPEN)
 |
 |--00:SCAN HDFS [tpcds.date_dim a]
@@ -234,7 +234,7 @@ PLAN-ROOT SINK
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=73049
 |     mem-estimate=48.00MB mem-reservation=8.00MB thread-reservation=1
-|     tuple-ids=0 row-size=303B cardinality=36525
+|     tuple-ids=0 row-size=255B cardinality=36525
 |     in pipelines: 00(GETNEXT)
 |
 01:SCAN HDFS [tpcds.date_dim b]
@@ -245,7 +245,7 @@ PLAN-ROOT SINK
      columns: all
    extrapolated-rows=disabled max-scan-range-rows=73049
    mem-estimate=48.00MB mem-reservation=8.00MB thread-reservation=1
-   tuple-ids=1 row-size=303B cardinality=73049
+   tuple-ids=1 row-size=255B cardinality=73049
    in pipelines: 01(GETNEXT)
 ====
 # Single query with various join types combined.
@@ -364,7 +364,7 @@ PLAN-ROOT SINK
 |  fk/pk conjuncts: assumed fk/pk
 |  runtime filters: RF000[bloom] <- c_customer_sk / 100
 |  mem-estimate=34.00MB mem-reservation=34.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=0,1 row-size=355B cardinality=2880404
+|  tuple-ids=0,1 row-size=319B cardinality=2880404
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--01:SCAN HDFS [tpcds.customer]
@@ -374,7 +374,7 @@ PLAN-ROOT SINK
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=100000
 |     mem-estimate=48.00MB mem-reservation=8.00MB thread-reservation=1
-|     tuple-ids=1 row-size=255B cardinality=100000
+|     tuple-ids=1 row-size=219B cardinality=100000
 |     in pipelines: 01(GETNEXT)
 |
 00:SCAN HDFS [tpcds.store_sales]

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/testdata/workloads/functional-planner/queries/PlannerTest/join-order.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/join-order.test b/testdata/workloads/functional-planner/queries/PlannerTest/join-order.test
index 3330b2e..fc6abeb 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/join-order.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/join-order.test
@@ -543,7 +543,6 @@ PLAN-ROOT SINK
    predicates: l_commitdate < l_receiptdate
    runtime filters: RF000 -> l_orderkey
 ====
-# the largest input is prevented from becoming the leftmost input by the full outer join
 select o_orderpriority, count(*) as order_count
 from tpch.orders
   full outer join tpch.lineitem
@@ -561,13 +560,13 @@ PLAN-ROOT SINK
 |  group by: o_orderpriority
 |
 02:HASH JOIN [FULL OUTER JOIN]
-|  hash predicates: o_orderkey = l_orderkey
+|  hash predicates: l_orderkey = o_orderkey
 |
-|--01:SCAN HDFS [tpch.lineitem]
-|     partitions=1/1 files=1 size=718.94MB
+|--00:SCAN HDFS [tpch.orders]
+|     partitions=1/1 files=1 size=162.56MB
 |
-00:SCAN HDFS [tpch.orders]
-   partitions=1/1 files=1 size=162.56MB
+01:SCAN HDFS [tpch.lineitem]
+   partitions=1/1 files=1 size=718.94MB
 ---- DISTRIBUTEDPLAN
 PLAN-ROOT SINK
 |
@@ -601,7 +600,6 @@ PLAN-ROOT SINK
 01:SCAN HDFS [tpch.lineitem]
    partitions=1/1 files=1 size=718.94MB
 ====
-# the largest input is prevented from becoming the leftmost input by the right outer join
 select o_orderpriority, count(*) as order_count
 from tpch.orders
   right outer join tpch.lineitem
@@ -618,16 +616,14 @@ PLAN-ROOT SINK
 |  output: count(*)
 |  group by: o_orderpriority
 |
-02:HASH JOIN [RIGHT OUTER JOIN]
-|  hash predicates: o_orderkey = l_orderkey
-|  runtime filters: RF000 <- l_orderkey
+02:HASH JOIN [LEFT OUTER JOIN]
+|  hash predicates: l_orderkey = o_orderkey
 |
-|--01:SCAN HDFS [tpch.lineitem]
-|     partitions=1/1 files=1 size=718.94MB
+|--00:SCAN HDFS [tpch.orders]
+|     partitions=1/1 files=1 size=162.56MB
 |
-00:SCAN HDFS [tpch.orders]
-   partitions=1/1 files=1 size=162.56MB
-   runtime filters: RF000 -> o_orderkey
+01:SCAN HDFS [tpch.lineitem]
+   partitions=1/1 files=1 size=718.94MB
 ---- DISTRIBUTEDPLAN
 PLAN-ROOT SINK
 |

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/testdata/workloads/functional-planner/queries/PlannerTest/max-row-size.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/max-row-size.test b/testdata/workloads/functional-planner/queries/PlannerTest/max-row-size.test
index 3ef04a7..87fcfb4 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/max-row-size.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/max-row-size.test
@@ -6,19 +6,19 @@ from tpch_parquet.customer
 ---- DISTRIBUTEDPLAN
 Max Per-Host Resource Reservation: Memory=33.97MB Threads=5
 Per-Host Resource Estimates: Memory=68MB
-Analyzed query: SELECT
+Analyzed query: SELECT 
 -- +straight_join
 * FROM tpch_parquet.customer INNER JOIN tpch_parquet.nation ON c_nationkey =
 n_nationkey
 
 F02:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=10.35MB mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=10.33MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 04:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=10.35MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=0,1 row-size=355B cardinality=150000
+|  mem-estimate=10.33MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=0,1 row-size=327B cardinality=150000
 |  in pipelines: 00(GETNEXT)
 |
 F00:PLAN FRAGMENT [RANDOM] hosts=1 instances=1
@@ -28,12 +28,12 @@ Per-Host Resources: mem-estimate=41.95MB mem-reservation=33.94MB thread-reservat
 |  fk/pk conjuncts: c_nationkey = n_nationkey
 |  runtime filters: RF000[bloom] <- n_nationkey
 |  mem-estimate=16.94MB mem-reservation=16.94MB spill-buffer=64.00KB thread-reservation=0
-|  tuple-ids=0,1 row-size=355B cardinality=150000
+|  tuple-ids=0,1 row-size=327B cardinality=150000
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--03:EXCHANGE [BROADCAST]
 |  |  mem-estimate=16.00KB mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=1 row-size=117B cardinality=25
+|  |  tuple-ids=1 row-size=109B cardinality=25
 |  |  in pipelines: 01(GETNEXT)
 |  |
 |  F01:PLAN FRAGMENT [RANDOM] hosts=1 instances=1
@@ -45,7 +45,7 @@ Per-Host Resources: mem-estimate=41.95MB mem-reservation=33.94MB thread-reservat
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=25
 |     mem-estimate=16.00MB mem-reservation=32.00KB thread-reservation=1
-|     tuple-ids=1 row-size=117B cardinality=25
+|     tuple-ids=1 row-size=109B cardinality=25
 |     in pipelines: 01(GETNEXT)
 |
 00:SCAN HDFS [tpch_parquet.customer, RANDOM]
@@ -56,7 +56,7 @@ Per-Host Resources: mem-estimate=41.95MB mem-reservation=33.94MB thread-reservat
      columns: all
    extrapolated-rows=disabled max-scan-range-rows=150000
    mem-estimate=24.00MB mem-reservation=16.00MB thread-reservation=1
-   tuple-ids=0 row-size=238B cardinality=150000
+   tuple-ids=0 row-size=218B cardinality=150000
    in pipelines: 00(GETNEXT)
 ====
 # Join with large build side.
@@ -66,34 +66,34 @@ from tpch_parquet.lineitem
     left join tpch_parquet.orders on l_orderkey = o_orderkey
 ---- DISTRIBUTEDPLAN
 Max Per-Host Resource Reservation: Memory=110.00MB Threads=5
-Per-Host Resource Estimates: Memory=442MB
-Analyzed query: SELECT
+Per-Host Resource Estimates: Memory=410MB
+Analyzed query: SELECT 
 -- +straight_join
 * FROM tpch_parquet.lineitem LEFT OUTER JOIN tpch_parquet.orders ON l_orderkey =
 o_orderkey
 
 F02:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=11.35MB mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=11.20MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 04:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=11.35MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=0,1N row-size=454B cardinality=6001215
+|  mem-estimate=11.20MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=0,1N row-size=402B cardinality=6001215
 |  in pipelines: 00(GETNEXT)
 |
 F00:PLAN FRAGMENT [RANDOM] hosts=3 instances=3
-Per-Host Resources: mem-estimate=390.80MB mem-reservation=86.00MB thread-reservation=2
+Per-Host Resources: mem-estimate=359.29MB mem-reservation=86.00MB thread-reservation=2
 02:HASH JOIN [LEFT OUTER JOIN, BROADCAST]
 |  hash predicates: l_orderkey = o_orderkey
 |  fk/pk conjuncts: l_orderkey = o_orderkey
-|  mem-estimate=300.41MB mem-reservation=46.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=0,1N row-size=454B cardinality=6001215
+|  mem-estimate=268.94MB mem-reservation=46.00MB spill-buffer=2.00MB thread-reservation=0
+|  tuple-ids=0,1N row-size=402B cardinality=6001215
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--03:EXCHANGE [BROADCAST]
-|  |  mem-estimate=10.38MB mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=1 row-size=191B cardinality=1500000
+|  |  mem-estimate=10.34MB mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=1 row-size=171B cardinality=1500000
 |  |  in pipelines: 01(GETNEXT)
 |  |
 |  F01:PLAN FRAGMENT [RANDOM] hosts=2 instances=2
@@ -105,7 +105,7 @@ Per-Host Resources: mem-estimate=390.80MB mem-reservation=86.00MB thread-reserva
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=1177135
 |     mem-estimate=40.00MB mem-reservation=24.00MB thread-reservation=1
-|     tuple-ids=1 row-size=191B cardinality=1500000
+|     tuple-ids=1 row-size=171B cardinality=1500000
 |     in pipelines: 01(GETNEXT)
 |
 00:SCAN HDFS [tpch_parquet.lineitem, RANDOM]
@@ -113,9 +113,9 @@ Per-Host Resources: mem-estimate=390.80MB mem-reservation=86.00MB thread-reserva
    stored statistics:
      table: rows=6001215 size=193.72MB
      columns: all
-   extrapolated-rows=disabled max-scan-range-rows=2141530
+   extrapolated-rows=disabled max-scan-range-rows=2141609
    mem-estimate=80.00MB mem-reservation=40.00MB thread-reservation=1
-   tuple-ids=0 row-size=263B cardinality=6001215
+   tuple-ids=0 row-size=231B cardinality=6001215
    in pipelines: 00(GETNEXT)
 ====
 # Null-aware anti-join with medium build side.
@@ -130,13 +130,13 @@ Analyzed query: SELECT * FROM tpch_parquet.lineitem NULL AWARE LEFT ANTI JOIN
 `$a$1`.`$c$1`
 
 F02:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=10.78MB mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=10.69MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 04:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=10.78MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=0 row-size=263B cardinality=6001215
+|  mem-estimate=10.69MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=0 row-size=231B cardinality=6001215
 |  in pipelines: 00(GETNEXT)
 |
 F00:PLAN FRAGMENT [RANDOM] hosts=3 instances=3
@@ -144,7 +144,7 @@ Per-Host Resources: mem-estimate=124.02MB mem-reservation=74.00MB thread-reserva
 02:HASH JOIN [NULL AWARE LEFT ANTI JOIN, BROADCAST]
 |  hash predicates: l_orderkey = o_orderkey
 |  mem-estimate=34.00MB mem-reservation=34.00MB spill-buffer=1.00MB thread-reservation=0
-|  tuple-ids=0 row-size=263B cardinality=6001215
+|  tuple-ids=0 row-size=231B cardinality=6001215
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--03:EXCHANGE [BROADCAST]
@@ -169,9 +169,9 @@ Per-Host Resources: mem-estimate=124.02MB mem-reservation=74.00MB thread-reserva
    stored statistics:
      table: rows=6001215 size=193.72MB
      columns: all
-   extrapolated-rows=disabled max-scan-range-rows=2141530
+   extrapolated-rows=disabled max-scan-range-rows=2141609
    mem-estimate=80.00MB mem-reservation=40.00MB thread-reservation=1
-   tuple-ids=0 row-size=263B cardinality=6001215
+   tuple-ids=0 row-size=231B cardinality=6001215
    in pipelines: 00(GETNEXT)
 ====
 # Mid NDV aggregation.
@@ -182,46 +182,46 @@ from tpch_parquet.lineitem
 group by 1, 2
 having count(*) = 1
 ---- DISTRIBUTEDPLAN
-Max Per-Host Resource Reservation: Memory=125.00MB Threads=7
-Per-Host Resource Estimates: Memory=293MB
-Analyzed query: SELECT
+Max Per-Host Resource Reservation: Memory=110.00MB Threads=7
+Per-Host Resource Estimates: Memory=272MB
+Analyzed query: SELECT 
 -- +straight_join
 l_orderkey, o_orderstatus, count(*) FROM tpch_parquet.lineitem INNER JOIN
 tpch_parquet.orders ON o_orderkey = l_orderkey GROUP BY CAST(1 AS INVALID_TYPE),
 CAST(2 AS INVALID_TYPE) HAVING count(*) = CAST(1 AS BIGINT)
 
 F04:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=10.11MB mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=10.10MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 08:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=10.11MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=2 row-size=33B cardinality=4690314
+|  mem-estimate=10.10MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=2 row-size=29B cardinality=4690314
 |  in pipelines: 07(GETNEXT)
 |
 F03:PLAN FRAGMENT [HASH(l_orderkey,o_orderstatus)] hosts=3 instances=3
-Per-Host Resources: mem-estimate=56.11MB mem-reservation=46.00MB thread-reservation=1
+Per-Host Resources: mem-estimate=41.10MB mem-reservation=31.00MB thread-reservation=1
 07:AGGREGATE [FINALIZE]
 |  output: count:merge(*)
 |  group by: l_orderkey, o_orderstatus
 |  having: count(*) = CAST(1 AS BIGINT)
-|  mem-estimate=46.00MB mem-reservation=46.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=2 row-size=33B cardinality=4690314
+|  mem-estimate=31.00MB mem-reservation=31.00MB spill-buffer=1.00MB thread-reservation=0
+|  tuple-ids=2 row-size=29B cardinality=4690314
 |  in pipelines: 07(GETNEXT), 00(OPEN)
 |
 06:EXCHANGE [HASH(l_orderkey,o_orderstatus)]
-|  mem-estimate=10.11MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=2 row-size=33B cardinality=4690314
+|  mem-estimate=10.10MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=2 row-size=29B cardinality=4690314
 |  in pipelines: 00(GETNEXT)
 |
 F02:PLAN FRAGMENT [HASH(l_orderkey)] hosts=3 instances=3
-Per-Host Resources: mem-estimate=106.22MB mem-reservation=66.00MB thread-reservation=1 runtime-filters-memory=1.00MB
+Per-Host Resources: mem-estimate=99.65MB mem-reservation=66.00MB thread-reservation=1 runtime-filters-memory=1.00MB
 03:AGGREGATE [STREAMING]
 |  output: count(*)
 |  group by: l_orderkey, o_orderstatus
-|  mem-estimate=54.12MB mem-reservation=34.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=2 row-size=33B cardinality=4690314
+|  mem-estimate=47.56MB mem-reservation=34.00MB spill-buffer=2.00MB thread-reservation=0
+|  tuple-ids=2 row-size=29B cardinality=4690314
 |  in pipelines: 00(GETNEXT)
 |
 02:HASH JOIN [INNER JOIN, PARTITIONED]
@@ -229,12 +229,12 @@ Per-Host Resources: mem-estimate=106.22MB mem-reservation=66.00MB thread-reserva
 |  fk/pk conjuncts: l_orderkey = o_orderkey
 |  runtime filters: RF000[bloom] <- o_orderkey
 |  mem-estimate=31.00MB mem-reservation=31.00MB spill-buffer=1.00MB thread-reservation=0
-|  tuple-ids=0,1 row-size=33B cardinality=5757710
+|  tuple-ids=0,1 row-size=29B cardinality=5757710
 |  in pipelines: 00(GETNEXT), 01(OPEN)
 |
 |--05:EXCHANGE [HASH(o_orderkey)]
-|  |  mem-estimate=10.06MB mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=1 row-size=25B cardinality=1500000
+|  |  mem-estimate=10.05MB mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=1 row-size=21B cardinality=1500000
 |  |  in pipelines: 01(GETNEXT)
 |  |
 |  F01:PLAN FRAGMENT [RANDOM] hosts=2 instances=2
@@ -246,7 +246,7 @@ Per-Host Resources: mem-estimate=106.22MB mem-reservation=66.00MB thread-reserva
 |       columns: all
 |     extrapolated-rows=disabled max-scan-range-rows=1177135
 |     mem-estimate=40.00MB mem-reservation=8.00MB thread-reservation=1
-|     tuple-ids=1 row-size=25B cardinality=1500000
+|     tuple-ids=1 row-size=21B cardinality=1500000
 |     in pipelines: 01(GETNEXT)
 |
 04:EXCHANGE [HASH(l_orderkey)]
@@ -262,7 +262,7 @@ Per-Host Resources: mem-estimate=81.00MB mem-reservation=5.00MB thread-reservati
    stored statistics:
      table: rows=6001215 size=193.72MB
      columns: all
-   extrapolated-rows=disabled max-scan-range-rows=2141530
+   extrapolated-rows=disabled max-scan-range-rows=2141609
    mem-estimate=80.00MB mem-reservation=4.00MB thread-reservation=1
    tuple-ids=0 row-size=8B cardinality=6001215
    in pipelines: 00(GETNEXT)
@@ -273,38 +273,38 @@ select distinct *
 from tpch_parquet.lineitem
 ---- DISTRIBUTEDPLAN
 Max Per-Host Resource Reservation: Memory=120.00MB Threads=4
-Per-Host Resource Estimates: Memory=1.71GB
+Per-Host Resource Estimates: Memory=1.52GB
 Analyzed query: SELECT DISTINCT * FROM tpch_parquet.lineitem
 
 F02:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=10.78MB mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=10.69MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 04:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=10.78MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=1 row-size=263B cardinality=6001215
+|  mem-estimate=10.69MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=1 row-size=231B cardinality=6001215
 |  in pipelines: 03(GETNEXT)
 |
 F01:PLAN FRAGMENT [HASH(tpch_parquet.lineitem.l_orderkey,tpch_parquet.lineitem.l_partkey,tpch_parquet.lineitem.l_suppkey,tpch_parquet.lineitem.l_linenumber,tpch_parquet.lineitem.l_quantity,tpch_parquet.lineitem.l_extendedprice,tpch_parquet.lineitem.l_discount,tpch_parquet.lineitem.l_tax,tpch_parquet.lineitem.l_returnflag,tpch_parquet.lineitem.l_linestatus,tpch_parquet.lineitem.l_shipdate,tpch_parquet.lineitem.l_commitdate,tpch_parquet.lineitem.l_receiptdate,tpch_parquet.lineitem.l_shipinstruct,tpch_parquet.lineitem.l_shipmode,tpch_parquet.lineitem.l_comment)] hosts=3 instances=3
-Per-Host Resources: mem-estimate=837.94MB mem-reservation=46.00MB thread-reservation=1
+Per-Host Resources: mem-estimate=737.12MB mem-reservation=46.00MB thread-reservation=1
 03:AGGREGATE [FINALIZE]
 |  group by: tpch_parquet.lineitem.l_orderkey, tpch_parquet.lineitem.l_partkey, tpch_parquet.lineitem.l_suppkey, tpch_parquet.lineitem.l_linenumber, tpch_parquet.lineitem.l_quantity, tpch_parquet.lineitem.l_extendedprice, tpch_parquet.lineitem.l_discount, tpch_parquet.lineitem.l_tax, tpch_parquet.lineitem.l_returnflag, tpch_parquet.lineitem.l_linestatus, tpch_parquet.lineitem.l_shipdate, tpch_parquet.lineitem.l_commitdate, tpch_parquet.lineitem.l_receiptdate, tpch_parquet.lineitem.l_shipinstruct, tpch_parquet.lineitem.l_shipmode, tpch_parquet.lineitem.l_comment
-|  mem-estimate=827.16MB mem-reservation=46.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=1 row-size=263B cardinality=6001215
+|  mem-estimate=726.43MB mem-reservation=46.00MB spill-buffer=2.00MB thread-reservation=0
+|  tuple-ids=1 row-size=231B cardinality=6001215
 |  in pipelines: 03(GETNEXT), 00(OPEN)
 |
 02:EXCHANGE [HASH(tpch_parquet.lineitem.l_orderkey,tpch_parquet.lineitem.l_partkey,tpch_parquet.lineitem.l_suppkey,tpch_parquet.lineitem.l_linenumber,tpch_parquet.lineitem.l_quantity,tpch_parquet.lineitem.l_extendedprice,tpch_parquet.lineitem.l_discount,tpch_parquet.lineitem.l_tax,tpch_parquet.lineitem.l_returnflag,tpch_parquet.lineitem.l_linestatus,tpch_parquet.lineitem.l_shipdate,tpch_parquet.lineitem.l_commitdate,tpch_parquet.lineitem.l_receiptdate,tpch_parquet.lineitem.l_shipinstruct,tpch_parquet.lineitem.l_shipmode,tpch_parquet.lineitem.l_comment)]
-|  mem-estimate=10.78MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=1 row-size=263B cardinality=6001215
+|  mem-estimate=10.69MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=1 row-size=231B cardinality=6001215
 |  in pipelines: 00(GETNEXT)
 |
 F00:PLAN FRAGMENT [RANDOM] hosts=3 instances=3
-Per-Host Resources: mem-estimate=907.16MB mem-reservation=74.00MB thread-reservation=2
+Per-Host Resources: mem-estimate=806.43MB mem-reservation=74.00MB thread-reservation=2
 01:AGGREGATE [STREAMING]
 |  group by: tpch_parquet.lineitem.l_orderkey, tpch_parquet.lineitem.l_partkey, tpch_parquet.lineitem.l_suppkey, tpch_parquet.lineitem.l_linenumber, tpch_parquet.lineitem.l_quantity, tpch_parquet.lineitem.l_extendedprice, tpch_parquet.lineitem.l_discount, tpch_parquet.lineitem.l_tax, tpch_parquet.lineitem.l_returnflag, tpch_parquet.lineitem.l_linestatus, tpch_parquet.lineitem.l_shipdate, tpch_parquet.lineitem.l_commitdate, tpch_parquet.lineitem.l_receiptdate, tpch_parquet.lineitem.l_shipinstruct, tpch_parquet.lineitem.l_shipmode, tpch_parquet.lineitem.l_comment
-|  mem-estimate=827.16MB mem-reservation=34.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=1 row-size=263B cardinality=6001215
+|  mem-estimate=726.43MB mem-reservation=34.00MB spill-buffer=2.00MB thread-reservation=0
+|  tuple-ids=1 row-size=231B cardinality=6001215
 |  in pipelines: 00(GETNEXT)
 |
 00:SCAN HDFS [tpch_parquet.lineitem, RANDOM]
@@ -312,9 +312,9 @@ Per-Host Resources: mem-estimate=907.16MB mem-reservation=74.00MB thread-reserva
    stored statistics:
      table: rows=6001215 size=193.72MB
      columns: all
-   extrapolated-rows=disabled max-scan-range-rows=2141530
+   extrapolated-rows=disabled max-scan-range-rows=2141609
    mem-estimate=80.00MB mem-reservation=40.00MB thread-reservation=1
-   tuple-ids=0 row-size=263B cardinality=6001215
+   tuple-ids=0 row-size=231B cardinality=6001215
    in pipelines: 00(GETNEXT)
 ====
 # High NDV aggregation with string aggregation function.
@@ -324,42 +324,42 @@ from tpch_parquet.lineitem
 group by 1, 2
 ---- DISTRIBUTEDPLAN
 Max Per-Host Resource Reservation: Memory=98.00MB Threads=4
-Per-Host Resource Estimates: Memory=302MB
+Per-Host Resource Estimates: Memory=276MB
 Analyzed query: SELECT l_orderkey, l_partkey, group_concat(l_linestatus, ',')
 FROM tpch_parquet.lineitem GROUP BY CAST(1 AS INVALID_TYPE), CAST(2 AS
 INVALID_TYPE)
 
 F02:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=10.11MB mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=10.09MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 04:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=10.11MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=1 row-size=32B cardinality=6001215
+|  mem-estimate=10.09MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=1 row-size=28B cardinality=6001215
 |  in pipelines: 03(GETNEXT)
 |
 F01:PLAN FRAGMENT [HASH(l_orderkey,l_partkey)] hosts=3 instances=3
-Per-Host Resources: mem-estimate=110.83MB mem-reservation=48.00MB thread-reservation=1
+Per-Host Resources: mem-estimate=98.23MB mem-reservation=48.00MB thread-reservation=1
 03:AGGREGATE [FINALIZE]
 |  output: group_concat:merge(l_linestatus, ',')
 |  group by: l_orderkey, l_partkey
-|  mem-estimate=100.73MB mem-reservation=48.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=1 row-size=32B cardinality=6001215
+|  mem-estimate=88.14MB mem-reservation=48.00MB spill-buffer=2.00MB thread-reservation=0
+|  tuple-ids=1 row-size=28B cardinality=6001215
 |  in pipelines: 03(GETNEXT), 00(OPEN)
 |
 02:EXCHANGE [HASH(l_orderkey,l_partkey)]
-|  mem-estimate=10.11MB mem-reservation=0B thread-reservation=0
-|  tuple-ids=1 row-size=32B cardinality=6001215
+|  mem-estimate=10.09MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=1 row-size=28B cardinality=6001215
 |  in pipelines: 00(GETNEXT)
 |
 F00:PLAN FRAGMENT [RANDOM] hosts=3 instances=3
-Per-Host Resources: mem-estimate=180.73MB mem-reservation=50.00MB thread-reservation=2
+Per-Host Resources: mem-estimate=168.14MB mem-reservation=50.00MB thread-reservation=2
 01:AGGREGATE [STREAMING]
 |  output: group_concat(l_linestatus, ',')
 |  group by: l_orderkey, l_partkey
-|  mem-estimate=100.73MB mem-reservation=34.00MB spill-buffer=2.00MB thread-reservation=0
-|  tuple-ids=1 row-size=32B cardinality=6001215
+|  mem-estimate=88.14MB mem-reservation=34.00MB spill-buffer=2.00MB thread-reservation=0
+|  tuple-ids=1 row-size=28B cardinality=6001215
 |  in pipelines: 00(GETNEXT)
 |
 00:SCAN HDFS [tpch_parquet.lineitem, RANDOM]
@@ -367,9 +367,9 @@ Per-Host Resources: mem-estimate=180.73MB mem-reservation=50.00MB thread-reserva
    stored statistics:
      table: rows=6001215 size=193.72MB
      columns: all
-   extrapolated-rows=disabled max-scan-range-rows=2141530
+   extrapolated-rows=disabled max-scan-range-rows=2141609
    mem-estimate=80.00MB mem-reservation=16.00MB thread-reservation=1
-   tuple-ids=0 row-size=33B cardinality=6001215
+   tuple-ids=0 row-size=29B cardinality=6001215
    in pipelines: 00(GETNEXT)
 ====
 # Sort + Analytic.

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/testdata/workloads/functional-planner/queries/PlannerTest/mt-dop-validation.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/mt-dop-validation.test b/testdata/workloads/functional-planner/queries/PlannerTest/mt-dop-validation.test
index c01e8a0..a1571b5 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/mt-dop-validation.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/mt-dop-validation.test
@@ -72,19 +72,19 @@ PLAN-ROOT SINK
    in pipelines: 00(GETNEXT)
 ---- PARALLELPLANS
 F02:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=0B mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=16.00KB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 05:MERGING-EXCHANGE [UNPARTITIONED]
 |  order by: count(int_col) ASC, bigint_col ASC
 |  limit: 10
-|  mem-estimate=0B mem-reservation=0B thread-reservation=0
+|  mem-estimate=16.00KB mem-reservation=0B thread-reservation=0
 |  tuple-ids=2 row-size=16B cardinality=10
 |  in pipelines: 02(GETNEXT)
 |
 F01:PLAN FRAGMENT [HASH(bigint_col)] hosts=3 instances=9
-Per-Host Resources: mem-estimate=384.00MB mem-reservation=102.00MB thread-reservation=3
+Per-Host Resources: mem-estimate=384.53MB mem-reservation=102.00MB thread-reservation=3
 02:TOP-N [LIMIT=10]
 |  order by: count(int_col) ASC, bigint_col ASC
 |  mem-estimate=160B mem-reservation=0B thread-reservation=0
@@ -99,7 +99,7 @@ Per-Host Resources: mem-estimate=384.00MB mem-reservation=102.00MB thread-reserv
 |  in pipelines: 04(GETNEXT), 00(OPEN)
 |
 03:EXCHANGE [HASH(bigint_col)]
-|  mem-estimate=0B mem-reservation=0B thread-reservation=0
+|  mem-estimate=180.00KB mem-reservation=0B thread-reservation=0
 |  tuple-ids=1 row-size=16B cardinality=unavailable
 |  in pipelines: 00(GETNEXT)
 |
@@ -166,17 +166,17 @@ PLAN-ROOT SINK
    in pipelines: 00(GETNEXT)
 ---- PARALLELPLANS
 F02:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=0B mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=216.00KB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 04:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=0B mem-reservation=0B thread-reservation=0
+|  mem-estimate=216.00KB mem-reservation=0B thread-reservation=0
 |  tuple-ids=4,3 row-size=16B cardinality=unavailable
 |  in pipelines: 01(GETNEXT)
 |
 F01:PLAN FRAGMENT [HASH(int_col)] hosts=3 instances=9
-Per-Host Resources: mem-estimate=30.00MB mem-reservation=30.00MB thread-reservation=3
+Per-Host Resources: mem-estimate=30.32MB mem-reservation=30.00MB thread-reservation=3
 02:ANALYTIC
 |  functions: row_number()
 |  partition by: int_col
@@ -193,7 +193,7 @@ Per-Host Resources: mem-estimate=30.00MB mem-reservation=30.00MB thread-reservat
 |  in pipelines: 01(GETNEXT), 00(OPEN)
 |
 03:EXCHANGE [HASH(int_col)]
-|  mem-estimate=0B mem-reservation=0B thread-reservation=0
+|  mem-estimate=108.00KB mem-reservation=0B thread-reservation=0
 |  tuple-ids=0 row-size=8B cardinality=unavailable
 |  in pipelines: 00(GETNEXT)
 |
@@ -225,34 +225,34 @@ PLAN-ROOT SINK
 |
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=2,1,0 row-size=562B cardinality=1500000
+|  tuple-ids=2,1,0 row-size=482B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 |--08:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=254B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1,0 row-size=562B cardinality=100
+|  |  mem-estimate=230B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=2,1,0 row-size=482B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=254B cardinality=1
+|  |     tuple-ids=0 row-size=230B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  04:SUBPLAN
 |  |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1 row-size=308B cardinality=100
+|  |  tuple-ids=2,1 row-size=252B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--07:NESTED LOOP JOIN [CROSS JOIN]
-|  |  |  mem-estimate=124B mem-reservation=0B thread-reservation=0
-|  |  |  tuple-ids=2,1 row-size=308B cardinality=10
+|  |  |  mem-estimate=100B mem-reservation=0B thread-reservation=0
+|  |  |  tuple-ids=2,1 row-size=252B cardinality=10
 |  |  |  in pipelines: 00(GETNEXT)
 |  |  |
 |  |  |--05:SINGULAR ROW SRC
 |  |  |     parent-subplan=04
 |  |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  |     tuple-ids=1 row-size=124B cardinality=1
+|  |  |     tuple-ids=1 row-size=100B cardinality=1
 |  |  |     in pipelines: 00(GETNEXT)
 |  |  |
 |  |  06:UNNEST [o.o_lineitems]
@@ -273,7 +273,7 @@ PLAN-ROOT SINK
    predicates on o: !empty(o.o_lineitems), o_orderkey < CAST(5 AS BIGINT)
    predicates on o_lineitems: l_linenumber < CAST(3 AS INT)
    stored statistics:
-     table: rows=150000 size=288.98MB
+     table: rows=150000 size=288.99MB
      columns missing stats: c_orders
    extrapolated-rows=disabled max-scan-range-rows=44227
    parquet statistics predicates: c_custkey < CAST(10 AS BIGINT)
@@ -283,51 +283,51 @@ PLAN-ROOT SINK
    parquet dictionary predicates on o: o_orderkey < CAST(5 AS BIGINT)
    parquet dictionary predicates on o_lineitems: l_linenumber < CAST(3 AS INT)
    mem-estimate=88.00MB mem-reservation=88.00MB thread-reservation=0
-   tuple-ids=0 row-size=254B cardinality=15000
+   tuple-ids=0 row-size=230B cardinality=15000
    in pipelines: 00(GETNEXT)
 ---- PARALLELPLANS
 F01:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=0B mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=14.34MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 09:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=2,1,0 row-size=562B cardinality=1500000
+|  mem-estimate=14.34MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=2,1,0 row-size=482B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 F00:PLAN FRAGMENT [RANDOM] hosts=3 instances=9
 Per-Host Resources: mem-estimate=264.00MB mem-reservation=264.00MB thread-reservation=3
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=2,1,0 row-size=562B cardinality=1500000
+|  tuple-ids=2,1,0 row-size=482B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 |--08:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=254B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1,0 row-size=562B cardinality=100
+|  |  mem-estimate=230B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=2,1,0 row-size=482B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=254B cardinality=1
+|  |     tuple-ids=0 row-size=230B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  04:SUBPLAN
 |  |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1 row-size=308B cardinality=100
+|  |  tuple-ids=2,1 row-size=252B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--07:NESTED LOOP JOIN [CROSS JOIN]
-|  |  |  mem-estimate=124B mem-reservation=0B thread-reservation=0
-|  |  |  tuple-ids=2,1 row-size=308B cardinality=10
+|  |  |  mem-estimate=100B mem-reservation=0B thread-reservation=0
+|  |  |  tuple-ids=2,1 row-size=252B cardinality=10
 |  |  |  in pipelines: 00(GETNEXT)
 |  |  |
 |  |  |--05:SINGULAR ROW SRC
 |  |  |     parent-subplan=04
 |  |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  |     tuple-ids=1 row-size=124B cardinality=1
+|  |  |     tuple-ids=1 row-size=100B cardinality=1
 |  |  |     in pipelines: 00(GETNEXT)
 |  |  |
 |  |  06:UNNEST [o.o_lineitems]
@@ -348,7 +348,7 @@ Per-Host Resources: mem-estimate=264.00MB mem-reservation=264.00MB thread-reserv
    predicates on o: !empty(o.o_lineitems), o_orderkey < CAST(5 AS BIGINT)
    predicates on o_lineitems: l_linenumber < CAST(3 AS INT)
    stored statistics:
-     table: rows=150000 size=288.98MB
+     table: rows=150000 size=288.99MB
      columns missing stats: c_orders
    extrapolated-rows=disabled max-scan-range-rows=44229
    parquet statistics predicates: c_custkey < CAST(10 AS BIGINT)
@@ -358,7 +358,7 @@ Per-Host Resources: mem-estimate=264.00MB mem-reservation=264.00MB thread-reserv
    parquet dictionary predicates on o: o_orderkey < CAST(5 AS BIGINT)
    parquet dictionary predicates on o_lineitems: l_linenumber < CAST(3 AS INT)
    mem-estimate=88.00MB mem-reservation=88.00MB thread-reservation=0
-   tuple-ids=0 row-size=254B cardinality=15000
+   tuple-ids=0 row-size=230B cardinality=15000
    in pipelines: 00(GETNEXT)
 ====
 # Hash-join in a subplan should work.
@@ -373,14 +373,14 @@ PLAN-ROOT SINK
 |
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=1,0,2 row-size=286B cardinality=1500000
+|  tuple-ids=1,0,2 row-size=258B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 |--06:HASH JOIN [INNER JOIN]
 |  |  hash predicates: o1.o_orderkey = o2.o_orderkey + 2
 |  |  fk/pk conjuncts: assumed fk/pk
 |  |  mem-estimate=1.94MB mem-reservation=1.94MB spill-buffer=64.00KB thread-reservation=0
-|  |  tuple-ids=1,0,2 row-size=286B cardinality=10
+|  |  tuple-ids=1,0,2 row-size=258B cardinality=10
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--04:UNNEST [c.c_orders o2]
@@ -390,14 +390,14 @@ PLAN-ROOT SINK
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  05:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=270B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=1,0 row-size=278B cardinality=10
+|  |  mem-estimate=242B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=1,0 row-size=250B cardinality=10
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=270B cardinality=1
+|  |     tuple-ids=0 row-size=242B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  03:UNNEST [c.c_orders o1]
@@ -407,41 +407,41 @@ PLAN-ROOT SINK
 |     in pipelines: 00(GETNEXT)
 |
 00:SCAN HDFS [tpch_nested_parquet.customer c]
-   partitions=1/1 files=4 size=288.98MB
+   partitions=1/1 files=4 size=288.99MB
    predicates: !empty(c.c_orders), !empty(c.c_orders)
    predicates on o1: o1.o_orderkey < CAST(5 AS BIGINT)
    stored statistics:
-     table: rows=150000 size=288.98MB
+     table: rows=150000 size=288.99MB
      columns missing stats: c_orders, c_orders
    extrapolated-rows=disabled max-scan-range-rows=44229
    parquet statistics predicates on o1: o1.o_orderkey < CAST(5 AS BIGINT)
    parquet dictionary predicates on o1: o1.o_orderkey < CAST(5 AS BIGINT)
    mem-estimate=88.00MB mem-reservation=16.00MB thread-reservation=0
-   tuple-ids=0 row-size=270B cardinality=150000
+   tuple-ids=0 row-size=242B cardinality=150000
    in pipelines: 00(GETNEXT)
 ---- PARALLELPLANS
 F01:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=0B mem-reservation=0B thread-reservation=1
+|  Per-Host Resources: mem-estimate=12.37MB mem-reservation=0B thread-reservation=1
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
 07:EXCHANGE [UNPARTITIONED]
-|  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=1,0,2 row-size=286B cardinality=1500000
+|  mem-estimate=12.37MB mem-reservation=0B thread-reservation=0
+|  tuple-ids=1,0,2 row-size=258B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 F00:PLAN FRAGMENT [RANDOM] hosts=3 instances=9
 Per-Host Resources: mem-estimate=269.81MB mem-reservation=53.81MB thread-reservation=3
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=1,0,2 row-size=286B cardinality=1500000
+|  tuple-ids=1,0,2 row-size=258B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 |--06:HASH JOIN [INNER JOIN]
 |  |  hash predicates: o1.o_orderkey = o2.o_orderkey + 2
 |  |  fk/pk conjuncts: assumed fk/pk
 |  |  mem-estimate=1.94MB mem-reservation=1.94MB spill-buffer=64.00KB thread-reservation=0
-|  |  tuple-ids=1,0,2 row-size=286B cardinality=10
+|  |  tuple-ids=1,0,2 row-size=258B cardinality=10
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--04:UNNEST [c.c_orders o2]
@@ -451,14 +451,14 @@ Per-Host Resources: mem-estimate=269.81MB mem-reservation=53.81MB thread-reserva
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  05:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=270B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=1,0 row-size=278B cardinality=10
+|  |  mem-estimate=242B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=1,0 row-size=250B cardinality=10
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=270B cardinality=1
+|  |     tuple-ids=0 row-size=242B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  03:UNNEST [c.c_orders o1]
@@ -468,16 +468,16 @@ Per-Host Resources: mem-estimate=269.81MB mem-reservation=53.81MB thread-reserva
 |     in pipelines: 00(GETNEXT)
 |
 00:SCAN HDFS [tpch_nested_parquet.customer c, RANDOM]
-   partitions=1/1 files=4 size=288.98MB
+   partitions=1/1 files=4 size=288.99MB
    predicates: !empty(c.c_orders), !empty(c.c_orders)
    predicates on o1: o1.o_orderkey < CAST(5 AS BIGINT)
    stored statistics:
-     table: rows=150000 size=288.98MB
+     table: rows=150000 size=288.99MB
      columns missing stats: c_orders, c_orders
    extrapolated-rows=disabled max-scan-range-rows=44229
    parquet statistics predicates on o1: o1.o_orderkey < CAST(5 AS BIGINT)
    parquet dictionary predicates on o1: o1.o_orderkey < CAST(5 AS BIGINT)
    mem-estimate=88.00MB mem-reservation=16.00MB thread-reservation=0
-   tuple-ids=0 row-size=270B cardinality=150000
+   tuple-ids=0 row-size=242B cardinality=150000
    in pipelines: 00(GETNEXT)
 ====

http://git-wip-us.apache.org/repos/asf/impala/blob/2a4835cf/testdata/workloads/functional-planner/queries/PlannerTest/parquet-filtering-disabled.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/parquet-filtering-disabled.test b/testdata/workloads/functional-planner/queries/PlannerTest/parquet-filtering-disabled.test
index b744547..166ba26 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/parquet-filtering-disabled.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/parquet-filtering-disabled.test
@@ -65,7 +65,7 @@ PLAN-ROOT SINK
      columns missing stats: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col
    extrapolated-rows=disabled max-scan-range-rows=unavailable
    mem-estimate=128.00MB mem-reservation=88.00KB thread-reservation=1
-   tuple-ids=0 row-size=80B cardinality=unavailable
+   tuple-ids=0 row-size=72B cardinality=unavailable
    in pipelines: 00(GETNEXT)
 ====
 # Parquet predicates to be skipped:
@@ -95,7 +95,7 @@ PLAN-ROOT SINK
      columns: unavailable
    extrapolated-rows=disabled max-scan-range-rows=unavailable
    mem-estimate=48.00MB mem-reservation=24.00KB thread-reservation=1
-   tuple-ids=0 row-size=24B cardinality=unavailable
+   tuple-ids=0 row-size=20B cardinality=unavailable
    in pipelines: 00(GETNEXT)
 ====
 # Nested parquet predicates to be skipped:
@@ -111,34 +111,34 @@ PLAN-ROOT SINK
 |
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=2,1,0 row-size=44B cardinality=unavailable
+|  tuple-ids=2,1,0 row-size=36B cardinality=unavailable
 |  in pipelines: 00(GETNEXT)
 |
 |--08:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=24B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1,0 row-size=44B cardinality=100
+|  |  mem-estimate=20B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=2,1,0 row-size=36B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=24B cardinality=1
+|  |     tuple-ids=0 row-size=20B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  04:SUBPLAN
 |  |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1 row-size=20B cardinality=100
+|  |  tuple-ids=2,1 row-size=16B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--07:NESTED LOOP JOIN [CROSS JOIN]
-|  |  |  mem-estimate=16B mem-reservation=0B thread-reservation=0
-|  |  |  tuple-ids=2,1 row-size=20B cardinality=10
+|  |  |  mem-estimate=12B mem-reservation=0B thread-reservation=0
+|  |  |  tuple-ids=2,1 row-size=16B cardinality=10
 |  |  |  in pipelines: 00(GETNEXT)
 |  |  |
 |  |  |--05:SINGULAR ROW SRC
 |  |  |     parent-subplan=04
 |  |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  |     tuple-ids=1 row-size=16B cardinality=1
+|  |  |     tuple-ids=1 row-size=12B cardinality=1
 |  |  |     in pipelines: 00(GETNEXT)
 |  |  |
 |  |  06:UNNEST [cn.item a]
@@ -163,7 +163,7 @@ PLAN-ROOT SINK
      columns missing stats: id
    extrapolated-rows=disabled max-scan-range-rows=unavailable
    mem-estimate=48.00MB mem-reservation=24.00KB thread-reservation=1
-   tuple-ids=0 row-size=24B cardinality=unavailable
+   tuple-ids=0 row-size=20B cardinality=unavailable
    in pipelines: 00(GETNEXT)
 ====
 # Parquet predicates to be skipped at each level:
@@ -179,34 +179,34 @@ PLAN-ROOT SINK
 |
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=2,1,0 row-size=56B cardinality=1500000
+|  tuple-ids=2,1,0 row-size=48B cardinality=1500000
 |  in pipelines: 00(GETNEXT)
 |
 |--08:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=24B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1,0 row-size=56B cardinality=100
+|  |  mem-estimate=20B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=2,1,0 row-size=48B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=24B cardinality=1
+|  |     tuple-ids=0 row-size=20B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  04:SUBPLAN
 |  |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1 row-size=32B cardinality=100
+|  |  tuple-ids=2,1 row-size=28B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--07:NESTED LOOP JOIN [CROSS JOIN]
-|  |  |  mem-estimate=24B mem-reservation=0B thread-reservation=0
-|  |  |  tuple-ids=2,1 row-size=32B cardinality=10
+|  |  |  mem-estimate=20B mem-reservation=0B thread-reservation=0
+|  |  |  tuple-ids=2,1 row-size=28B cardinality=10
 |  |  |  in pipelines: 00(GETNEXT)
 |  |  |
 |  |  |--05:SINGULAR ROW SRC
 |  |  |     parent-subplan=04
 |  |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  |     tuple-ids=1 row-size=24B cardinality=1
+|  |  |     tuple-ids=1 row-size=20B cardinality=1
 |  |  |     in pipelines: 00(GETNEXT)
 |  |  |
 |  |  06:UNNEST [o.o_lineitems l]
@@ -227,11 +227,11 @@ PLAN-ROOT SINK
    predicates on o: !empty(o.o_lineitems), o.o_orderkey > CAST(0 AS BIGINT)
    predicates on l: l.l_partkey > CAST(0 AS BIGINT)
    stored statistics:
-     table: rows=150000 size=288.98MB
+     table: rows=150000 size=288.96MB
      columns missing stats: c_orders
-   extrapolated-rows=disabled max-scan-range-rows=44229
+   extrapolated-rows=disabled max-scan-range-rows=44226
    mem-estimate=264.00MB mem-reservation=16.00MB thread-reservation=1
-   tuple-ids=0 row-size=24B cardinality=15000
+   tuple-ids=0 row-size=20B cardinality=15000
    in pipelines: 00(GETNEXT)
 ====
 # Parquet filtering to be skipped on multiple collections at the same nested level:
@@ -252,34 +252,34 @@ PLAN-ROOT SINK
 |
 01:SUBPLAN
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  tuple-ids=2,1,0 row-size=162B cardinality=15000000
+|  tuple-ids=2,1,0 row-size=126B cardinality=15000000
 |  in pipelines: 00(GETNEXT)
 |
 |--08:NESTED LOOP JOIN [CROSS JOIN]
-|  |  mem-estimate=50B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1,0 row-size=162B cardinality=100
+|  |  mem-estimate=42B mem-reservation=0B thread-reservation=0
+|  |  tuple-ids=2,1,0 row-size=126B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--02:SINGULAR ROW SRC
 |  |     parent-subplan=01
 |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |     tuple-ids=0 row-size=50B cardinality=1
+|  |     tuple-ids=0 row-size=42B cardinality=1
 |  |     in pipelines: 00(GETNEXT)
 |  |
 |  04:SUBPLAN
 |  |  mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  tuple-ids=2,1 row-size=112B cardinality=100
+|  |  tuple-ids=2,1 row-size=84B cardinality=100
 |  |  in pipelines: 00(GETNEXT)
 |  |
 |  |--07:NESTED LOOP JOIN [CROSS JOIN]
-|  |  |  mem-estimate=32B mem-reservation=0B thread-reservation=0
-|  |  |  tuple-ids=2,1 row-size=112B cardinality=10
+|  |  |  mem-estimate=24B mem-reservation=0B thread-reservation=0
+|  |  |  tuple-ids=2,1 row-size=84B cardinality=10
 |  |  |  in pipelines: 00(GETNEXT)
 |  |  |
 |  |  |--05:SINGULAR ROW SRC
 |  |  |     parent-subplan=04
 |  |  |     mem-estimate=0B mem-reservation=0B thread-reservation=0
-|  |  |     tuple-ids=1 row-size=32B cardinality=1
+|  |  |     tuple-ids=1 row-size=24B cardinality=1
 |  |  |     in pipelines: 00(GETNEXT)
 |  |  |
 |  |  06:UNNEST [o.o_lineitems l]
@@ -295,16 +295,16 @@ PLAN-ROOT SINK
 |     in pipelines: 00(GETNEXT)
 |
 00:SCAN HDFS [tpch_nested_parquet.customer c]
-   partitions=1/1 files=4 size=288.98MB
+   partitions=1/1 files=4 size=288.96MB
    predicates: !empty(c.c_orders)
    predicates on o: !empty(o.o_lineitems)
    predicates on l: l.l_shipdate = '1994-08-19', l.l_receiptdate = '1994-08-24', l.l_shipmode = 'RAIL', l.l_returnflag = 'R', l.l_comment IS NULL
    stored statistics:
-     table: rows=150000 size=288.98MB
+     table: rows=150000 size=288.96MB
      columns missing stats: c_orders
-   extrapolated-rows=disabled max-scan-range-rows=44229
+   extrapolated-rows=disabled max-scan-range-rows=44226
    mem-estimate=616.00MB mem-reservation=32.00MB thread-reservation=1
-   tuple-ids=0 row-size=50B cardinality=150000
+   tuple-ids=0 row-size=42B cardinality=150000
    in pipelines: 00(GETNEXT)
 ====
 # Parquet filtering to be skipped on a mixed file format table:
@@ -322,7 +322,7 @@ and timestamp_cmp(timestamp_col, '2016-11-20 00:00:00') = 1
 and year > 2000 and month < 12;
 ---- PLAN
 F00:PLAN FRAGMENT [UNPARTITIONED] hosts=1 instances=1
-|  Per-Host Resources: mem-estimate=42.00MB mem-reservation=88.00KB thread-reservation=2
+|  Per-Host Resources: mem-estimate=138.00MB mem-reservation=88.00KB thread-reservation=2
 PLAN-ROOT SINK
 |  mem-estimate=0B mem-reservation=0B thread-reservation=0
 |
@@ -341,6 +341,6 @@ PLAN-ROOT SINK
      columns missing stats: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col
    extrapolated-rows=disabled max-scan-range-rows=unavailable
    mem-estimate=128.00MB mem-reservation=88.00KB thread-reservation=1
-   tuple-ids=0 row-size=80B cardinality=unavailable
+   tuple-ids=0 row-size=72B cardinality=unavailable
    in pipelines: 00(GETNEXT)
 ====