You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ag...@apache.org on 2022/06/04 20:59:12 UTC

[arrow-datafusion] branch master updated: Show column names instead of indices in query plans (#2690)

This is an automated email from the ASF dual-hosted git repository.

agrove pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/master by this push:
     new c65feeb0c Show column names instead of indices in query plans (#2690)
c65feeb0c is described below

commit c65feeb0ce4177b9e7bc1209fdd9a32caec0d2e6
Author: Andy Grove <ag...@apache.org>
AuthorDate: Sat Jun 4 14:59:07 2022 -0600

    Show column names instead of indices in query plans (#2690)
---
 datafusion/core/src/datasource/view.rs           | 58 ++++++++++++------------
 datafusion/core/src/logical_plan/plan.rs         |  8 ++--
 datafusion/core/tests/custom_sources.rs          |  2 +-
 datafusion/core/tests/sql/avro.rs                |  2 +-
 datafusion/core/tests/sql/explain_analyze.rs     | 26 +++++------
 datafusion/core/tests/sql/json.rs                |  2 +-
 datafusion/core/tests/sql/projection.rs          |  4 +-
 datafusion/core/tests/sql/udf.rs                 |  2 +-
 datafusion/core/tests/user_defined_plan.rs       |  2 +-
 datafusion/expr/src/logical_plan/builder.rs      | 14 +++---
 datafusion/expr/src/logical_plan/plan.rs         | 16 ++++++-
 datafusion/optimizer/src/filter_push_down.rs     |  2 +-
 datafusion/optimizer/src/projection_push_down.rs | 44 +++++++++---------
 13 files changed, 97 insertions(+), 85 deletions(-)

diff --git a/datafusion/core/src/datasource/view.rs b/datafusion/core/src/datasource/view.rs
index 18a43d3d4..7ea5329eb 100644
--- a/datafusion/core/src/datasource/view.rs
+++ b/datafusion/core/src/datasource/view.rs
@@ -262,15 +262,15 @@ mod tests {
             .await?;
 
         let expected = vec![
-            "+---------------+--------------------------------------------------------+",
-            "| plan_type     | plan                                                   |",
-            "+---------------+--------------------------------------------------------+",
-            "| logical_plan  | CreateView: \"xyz\"                                      |",
-            "|               |   Projection: #abc.column1, #abc.column2, #abc.column3 |",
-            "|               |     TableScan: abc projection=Some([0, 1, 2])          |",
-            "| physical_plan | EmptyExec: produce_one_row=false                       |",
-            "|               |                                                        |",
-            "+---------------+--------------------------------------------------------+",
+            "+---------------+-----------------------------------------------------------------+",
+            "| plan_type     | plan                                                            |",
+            "+---------------+-----------------------------------------------------------------+",
+            "| logical_plan  | CreateView: \"xyz\"                                               |",
+            "|               |   Projection: #abc.column1, #abc.column2, #abc.column3          |",
+            "|               |     TableScan: abc projection=Some([column1, column2, column3]) |",
+            "| physical_plan | EmptyExec: produce_one_row=false                                |",
+            "|               |                                                                 |",
+            "+---------------+-----------------------------------------------------------------+",
         ];
 
         assert_batches_eq!(expected, &results);
@@ -282,16 +282,16 @@ mod tests {
             .await?;
 
         let expected = vec![
-            "+---------------+--------------------------------------------------------+",
-            "| plan_type     | plan                                                   |",
-            "+---------------+--------------------------------------------------------+",
-            "| logical_plan  | CreateView: \"xyz\"                                      |",
-            "|               |   Projection: #abc.column1, #abc.column2, #abc.column3 |",
-            "|               |     Filter: #abc.column2 = Int64(5)                    |",
-            "|               |       TableScan: abc projection=Some([0, 1, 2])        |",
-            "| physical_plan | EmptyExec: produce_one_row=false                       |",
-            "|               |                                                        |",
-            "+---------------+--------------------------------------------------------+",
+            "+---------------+-------------------------------------------------------------------+",
+            "| plan_type     | plan                                                              |",
+            "+---------------+-------------------------------------------------------------------+",
+            "| logical_plan  | CreateView: \"xyz\"                                                 |",
+            "|               |   Projection: #abc.column1, #abc.column2, #abc.column3            |",
+            "|               |     Filter: #abc.column2 = Int64(5)                               |",
+            "|               |       TableScan: abc projection=Some([column1, column2, column3]) |",
+            "| physical_plan | EmptyExec: produce_one_row=false                                  |",
+            "|               |                                                                   |",
+            "+---------------+-------------------------------------------------------------------+",
         ];
 
         assert_batches_eq!(expected, &results);
@@ -303,16 +303,16 @@ mod tests {
             .await?;
 
         let expected = vec![
-            "+---------------+----------------------------------------------+",
-            "| plan_type     | plan                                         |",
-            "+---------------+----------------------------------------------+",
-            "| logical_plan  | CreateView: \"xyz\"                            |",
-            "|               |   Projection: #abc.column1, #abc.column2     |",
-            "|               |     Filter: #abc.column2 = Int64(5)          |",
-            "|               |       TableScan: abc projection=Some([0, 1]) |",
-            "| physical_plan | EmptyExec: produce_one_row=false             |",
-            "|               |                                              |",
-            "+---------------+----------------------------------------------+",
+            "+---------------+----------------------------------------------------------+",
+            "| plan_type     | plan                                                     |",
+            "+---------------+----------------------------------------------------------+",
+            "| logical_plan  | CreateView: \"xyz\"                                        |",
+            "|               |   Projection: #abc.column1, #abc.column2                 |",
+            "|               |     Filter: #abc.column2 = Int64(5)                      |",
+            "|               |       TableScan: abc projection=Some([column1, column2]) |",
+            "| physical_plan | EmptyExec: produce_one_row=false                         |",
+            "|               |                                                          |",
+            "+---------------+----------------------------------------------------------+",
         ];
 
         assert_batches_eq!(expected, &results);
diff --git a/datafusion/core/src/logical_plan/plan.rs b/datafusion/core/src/logical_plan/plan.rs
index 1dfda1a86..0ef1ecd81 100644
--- a/datafusion/core/src/logical_plan/plan.rs
+++ b/datafusion/core/src/logical_plan/plan.rs
@@ -132,7 +132,7 @@ mod tests {
 
         let expected = "Projection: #employee_csv.id\
         \n  Filter: #employee_csv.state = Utf8(\"CO\")\
-        \n    TableScan: employee_csv projection=Some([0, 3])";
+        \n    TableScan: employee_csv projection=Some([id, state])";
 
         assert_eq!(expected, format!("{}", plan.display_indent()));
     }
@@ -143,7 +143,7 @@ mod tests {
 
         let expected = "Projection: #employee_csv.id [id:Int32]\
                         \n  Filter: #employee_csv.state = Utf8(\"CO\") [id:Int32, state:Utf8]\
-                        \n    TableScan: employee_csv projection=Some([0, 3]) [id:Int32, state:Utf8]";
+                        \n    TableScan: employee_csv projection=Some([id, state]) [id:Int32, state:Utf8]";
 
         assert_eq!(expected, format!("{}", plan.display_indent_schema()));
     }
@@ -165,12 +165,12 @@ mod tests {
         );
         assert!(
             graphviz.contains(
-                r#"[shape=box label="TableScan: employee_csv projection=Some([0, 3])"]"#
+                r#"[shape=box label="TableScan: employee_csv projection=Some([id, state])"]"#
             ),
             "\n{}",
             plan.display_graphviz()
         );
-        assert!(graphviz.contains(r#"[shape=box label="TableScan: employee_csv projection=Some([0, 3])\nSchema: [id:Int32, state:Utf8]"]"#),
+        assert!(graphviz.contains(r#"[shape=box label="TableScan: employee_csv projection=Some([id, state])\nSchema: [id:Int32, state:Utf8]"]"#),
                 "\n{}", plan.display_graphviz());
         assert!(
             graphviz.contains(r#"// End DataFusion GraphViz Plan"#),
diff --git a/datafusion/core/tests/custom_sources.rs b/datafusion/core/tests/custom_sources.rs
index cccac0523..c28619373 100644
--- a/datafusion/core/tests/custom_sources.rs
+++ b/datafusion/core/tests/custom_sources.rs
@@ -239,7 +239,7 @@ async fn custom_source_dataframe() -> Result<()> {
 
     let expected = format!(
         "Projection: #{}.c2\
-        \n  TableScan: {} projection=Some([1])",
+        \n  TableScan: {} projection=Some([c2])",
         UNNAMED_TABLE, UNNAMED_TABLE
     );
     assert_eq!(format!("{:?}", optimized_plan), expected);
diff --git a/datafusion/core/tests/sql/avro.rs b/datafusion/core/tests/sql/avro.rs
index 0102cf3b7..e756b435c 100644
--- a/datafusion/core/tests/sql/avro.rs
+++ b/datafusion/core/tests/sql/avro.rs
@@ -145,7 +145,7 @@ async fn avro_explain() {
             "logical_plan",
             "Projection: #COUNT(UInt8(1))\
             \n  Aggregate: groupBy=[[]], aggr=[[COUNT(UInt8(1))]]\
-            \n    TableScan: alltypes_plain projection=Some([0])",
+            \n    TableScan: alltypes_plain projection=Some([id])",
         ],
         vec![
             "physical_plan",
diff --git a/datafusion/core/tests/sql/explain_analyze.rs b/datafusion/core/tests/sql/explain_analyze.rs
index 472fe15d2..a25543b34 100644
--- a/datafusion/core/tests/sql/explain_analyze.rs
+++ b/datafusion/core/tests/sql/explain_analyze.rs
@@ -269,7 +269,7 @@ async fn csv_explain_plans() {
         "Explain [plan_type:Utf8, plan:Utf8]",
         "  Projection: #aggregate_test_100.c1 [c1:Utf8]",
         "    Filter: #aggregate_test_100.c2 > Int64(10) [c1:Utf8, c2:Int32]",
-        "      TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)] [c1:Utf8, c2:Int32]",
+        "      TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)] [c1:Utf8, c2:Int32]",
     ];
     let formatted = plan.display_indent_schema().to_string();
     let actual: Vec<&str> = formatted.trim().lines().collect();
@@ -284,7 +284,7 @@ async fn csv_explain_plans() {
         "Explain",
         "  Projection: #aggregate_test_100.c1",
         "    Filter: #aggregate_test_100.c2 > Int64(10)",
-        "      TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]",
+        "      TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]",
     ];
     let formatted = plan.display_indent().to_string();
     let actual: Vec<&str> = formatted.trim().lines().collect();
@@ -306,7 +306,7 @@ async fn csv_explain_plans() {
         "    2 -> 3 [arrowhead=none, arrowtail=normal, dir=back]",
         "    4[shape=box label=\"Filter: #aggregate_test_100.c2 > Int64(10)\"]",
         "    3 -> 4 [arrowhead=none, arrowtail=normal, dir=back]",
-        "    5[shape=box label=\"TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\"]",
+        "    5[shape=box label=\"TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\"]",
         "    4 -> 5 [arrowhead=none, arrowtail=normal, dir=back]",
         "  }",
         "  subgraph cluster_6",
@@ -317,7 +317,7 @@ async fn csv_explain_plans() {
         "    7 -> 8 [arrowhead=none, arrowtail=normal, dir=back]",
         "    9[shape=box label=\"Filter: #aggregate_test_100.c2 > Int64(10)\\nSchema: [c1:Utf8, c2:Int32]\"]",
         "    8 -> 9 [arrowhead=none, arrowtail=normal, dir=back]",
-        "    10[shape=box label=\"TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\\nSchema: [c1:Utf8, c2:Int32]\"]",
+        "    10[shape=box label=\"TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\\nSchema: [c1:Utf8, c2:Int32]\"]",
         "    9 -> 10 [arrowhead=none, arrowtail=normal, dir=back]",
         "  }",
         "}",
@@ -467,7 +467,7 @@ async fn csv_explain_verbose_plans() {
         "Explain [plan_type:Utf8, plan:Utf8]",
         "  Projection: #aggregate_test_100.c1 [c1:Utf8]",
         "    Filter: #aggregate_test_100.c2 > Int64(10) [c1:Utf8, c2:Int32]",
-        "      TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)] [c1:Utf8, c2:Int32]",
+        "      TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)] [c1:Utf8, c2:Int32]",
     ];
     let formatted = plan.display_indent_schema().to_string();
     let actual: Vec<&str> = formatted.trim().lines().collect();
@@ -482,7 +482,7 @@ async fn csv_explain_verbose_plans() {
         "Explain",
         "  Projection: #aggregate_test_100.c1",
         "    Filter: #aggregate_test_100.c2 > Int64(10)",
-        "      TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]",
+        "      TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]",
     ];
     let formatted = plan.display_indent().to_string();
     let actual: Vec<&str> = formatted.trim().lines().collect();
@@ -504,7 +504,7 @@ async fn csv_explain_verbose_plans() {
         "    2 -> 3 [arrowhead=none, arrowtail=normal, dir=back]",
         "    4[shape=box label=\"Filter: #aggregate_test_100.c2 > Int64(10)\"]",
         "    3 -> 4 [arrowhead=none, arrowtail=normal, dir=back]",
-        "    5[shape=box label=\"TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\"]",
+        "    5[shape=box label=\"TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\"]",
         "    4 -> 5 [arrowhead=none, arrowtail=normal, dir=back]",
         "  }",
         "  subgraph cluster_6",
@@ -515,7 +515,7 @@ async fn csv_explain_verbose_plans() {
         "    7 -> 8 [arrowhead=none, arrowtail=normal, dir=back]",
         "    9[shape=box label=\"Filter: #aggregate_test_100.c2 > Int64(10)\\nSchema: [c1:Utf8, c2:Int32]\"]",
         "    8 -> 9 [arrowhead=none, arrowtail=normal, dir=back]",
-        "    10[shape=box label=\"TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\\nSchema: [c1:Utf8, c2:Int32]\"]",
+        "    10[shape=box label=\"TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]\\nSchema: [c1:Utf8, c2:Int32]\"]",
         "    9 -> 10 [arrowhead=none, arrowtail=normal, dir=back]",
         "  }",
         "}",
@@ -628,12 +628,12 @@ order by
     \n      Inner Join: #customer.c_nationkey = #nation.n_nationkey\
     \n        Inner Join: #orders.o_orderkey = #lineitem.l_orderkey\
     \n          Inner Join: #customer.c_custkey = #orders.o_custkey\
-    \n            TableScan: customer projection=Some([0, 1, 2, 3, 4, 5, 7])\
+    \n            TableScan: customer projection=Some([c_custkey, c_name, c_address, c_nationkey, c_phone, c_acctbal, c_comment])\
     \n            Filter: #orders.o_orderdate >= Date32(\"8674\") AND #orders.o_orderdate < Date32(\"8766\")\
-    \n              TableScan: orders projection=Some([0, 1, 4]), partial_filters=[#orders.o_orderdate >= Date32(\"8674\"), #orders.o_orderdate < Date32(\"8766\")]\
+    \n              TableScan: orders projection=Some([o_orderkey, o_custkey, o_orderdate]), partial_filters=[#orders.o_orderdate >= Date32(\"8674\"), #orders.o_orderdate < Date32(\"8766\")]\
     \n          Filter: #lineitem.l_returnflag = Utf8(\"R\")\
-    \n            TableScan: lineitem projection=Some([0, 5, 6, 8]), partial_filters=[#lineitem.l_returnflag = Utf8(\"R\")]\
-    \n        TableScan: nation projection=Some([0, 1])";
+    \n            TableScan: lineitem projection=Some([l_orderkey, l_extendedprice, l_discount, l_returnflag]), partial_filters=[#lineitem.l_returnflag = Utf8(\"R\")]\
+    \n        TableScan: nation projection=Some([n_nationkey, n_name])";
     assert_eq!(format!("{:?}", plan.unwrap()), expected);
 
     Ok(())
@@ -753,7 +753,7 @@ async fn csv_explain() {
             "logical_plan",
             "Projection: #aggregate_test_100.c1\
              \n  Filter: #aggregate_test_100.c2 > Int64(10)\
-             \n    TableScan: aggregate_test_100 projection=Some([0, 1]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]"
+             \n    TableScan: aggregate_test_100 projection=Some([c1, c2]), partial_filters=[#aggregate_test_100.c2 > Int64(10)]"
         ],
         vec!["physical_plan",
              "ProjectionExec: expr=[c1@0 as c1]\
diff --git a/datafusion/core/tests/sql/json.rs b/datafusion/core/tests/sql/json.rs
index 99032092d..0fc63ee3a 100644
--- a/datafusion/core/tests/sql/json.rs
+++ b/datafusion/core/tests/sql/json.rs
@@ -88,7 +88,7 @@ async fn json_explain() {
             "logical_plan",
             "Projection: #COUNT(UInt8(1))\
             \n  Aggregate: groupBy=[[]], aggr=[[COUNT(UInt8(1))]]\
-            \n    TableScan: t1 projection=Some([0])",
+            \n    TableScan: t1 projection=Some([a])",
         ],
         vec![
             "physical_plan",
diff --git a/datafusion/core/tests/sql/projection.rs b/datafusion/core/tests/sql/projection.rs
index c74445bfd..63b247f21 100644
--- a/datafusion/core/tests/sql/projection.rs
+++ b/datafusion/core/tests/sql/projection.rs
@@ -188,7 +188,7 @@ async fn projection_on_table_scan() -> Result<()> {
     }
 
     let expected = "Projection: #test.c2\
-                    \n  TableScan: test projection=Some([1])";
+                    \n  TableScan: test projection=Some([c2])";
     assert_eq!(format!("{:?}", optimized_plan), expected);
 
     let physical_plan = ctx.create_physical_plan(&optimized_plan).await?;
@@ -264,7 +264,7 @@ async fn projection_on_memory_scan() -> Result<()> {
 
     let expected = format!(
         "Projection: #{}.b\
-         \n  TableScan: {} projection=Some([1])",
+         \n  TableScan: {} projection=Some([b])",
         UNNAMED_TABLE, UNNAMED_TABLE
     );
     assert_eq!(format!("{:?}", optimized_plan), expected);
diff --git a/datafusion/core/tests/sql/udf.rs b/datafusion/core/tests/sql/udf.rs
index 024bb20cb..d9bb4838b 100644
--- a/datafusion/core/tests/sql/udf.rs
+++ b/datafusion/core/tests/sql/udf.rs
@@ -92,7 +92,7 @@ async fn scalar_udf() -> Result<()> {
 
     assert_eq!(
         format!("{:?}", plan),
-        "Projection: #t.a, #t.b, my_add(#t.a, #t.b)\n  TableScan: t projection=Some([0, 1])"
+        "Projection: #t.a, #t.b, my_add(#t.a, #t.b)\n  TableScan: t projection=Some([a, b])"
     );
 
     let plan = ctx.optimize(&plan)?;
diff --git a/datafusion/core/tests/user_defined_plan.rs b/datafusion/core/tests/user_defined_plan.rs
index a1bbb2419..de94c63b5 100644
--- a/datafusion/core/tests/user_defined_plan.rs
+++ b/datafusion/core/tests/user_defined_plan.rs
@@ -219,7 +219,7 @@ async fn topk_plan() -> Result<()> {
     let mut expected = vec![
         "| logical_plan after topk                               | TopK: k=3                                                                     |",
         "|                                                       |   Projection: #sales.customer_id, #sales.revenue                              |",
-        "|                                                       |     TableScan: sales projection=Some([0, 1])                                  |",
+        "|                                                       |     TableScan: sales projection=Some([customer_id, revenue])                                  |",
     ].join("\n");
 
     let explain_query = format!("EXPLAIN VERBOSE {}", QUERY);
diff --git a/datafusion/expr/src/logical_plan/builder.rs b/datafusion/expr/src/logical_plan/builder.rs
index c7307dd3d..917606144 100644
--- a/datafusion/expr/src/logical_plan/builder.rs
+++ b/datafusion/expr/src/logical_plan/builder.rs
@@ -999,7 +999,7 @@ mod tests {
 
         let expected = "Projection: #employee_csv.id\
         \n  Filter: #employee_csv.state = Utf8(\"CO\")\
-        \n    TableScan: employee_csv projection=Some([0, 3])";
+        \n    TableScan: employee_csv projection=Some([id, state])";
 
         assert_eq!(expected, format!("{:?}", plan));
 
@@ -1034,7 +1034,7 @@ mod tests {
         \n  Limit: 10\
         \n    Projection: #employee_csv.state, #total_salary\
         \n      Aggregate: groupBy=[[#employee_csv.state]], aggr=[[SUM(#employee_csv.salary) AS total_salary]]\
-        \n        TableScan: employee_csv projection=Some([3, 4])";
+        \n        TableScan: employee_csv projection=Some([state, salary])";
 
         assert_eq!(expected, format!("{:?}", plan));
 
@@ -1060,7 +1060,7 @@ mod tests {
                 .build()?;
 
         let expected = "Sort: #employee_csv.state ASC NULLS FIRST, #employee_csv.salary DESC NULLS LAST\
-        \n  TableScan: employee_csv projection=Some([3, 4])";
+        \n  TableScan: employee_csv projection=Some([state, salary])";
 
         assert_eq!(expected, format!("{:?}", plan));
 
@@ -1100,10 +1100,10 @@ mod tests {
 
         // output has only one union
         let expected = "Union\
-        \n  TableScan: employee_csv projection=Some([3, 4])\
-        \n  TableScan: employee_csv projection=Some([3, 4])\
-        \n  TableScan: employee_csv projection=Some([3, 4])\
-        \n  TableScan: employee_csv projection=Some([3, 4])";
+        \n  TableScan: employee_csv projection=Some([state, salary])\
+        \n  TableScan: employee_csv projection=Some([state, salary])\
+        \n  TableScan: employee_csv projection=Some([state, salary])\
+        \n  TableScan: employee_csv projection=Some([state, salary])";
 
         assert_eq!(expected, format!("{:?}", plan));
 
diff --git a/datafusion/expr/src/logical_plan/plan.rs b/datafusion/expr/src/logical_plan/plan.rs
index bb3434a57..7174a4c77 100644
--- a/datafusion/expr/src/logical_plan/plan.rs
+++ b/datafusion/expr/src/logical_plan/plan.rs
@@ -656,10 +656,22 @@ impl LogicalPlan {
                         ref limit,
                         ..
                     }) => {
+                        let projected_fields = match projection {
+                            Some(indices) => {
+                                let schema = source.schema();
+                                let names: Vec<&str> = indices
+                                    .iter()
+                                    .map(|i| schema.field(*i).name().as_str())
+                                    .collect();
+                                format!("Some([{}])", names.join(", "))
+                            }
+                            _ => "None".to_string(),
+                        };
+
                         write!(
                             f,
-                            "TableScan: {} projection={:?}",
-                            table_name, projection
+                            "TableScan: {} projection={}",
+                            table_name, projected_fields
                         )?;
 
                         if !filters.is_empty() {
diff --git a/datafusion/optimizer/src/filter_push_down.rs b/datafusion/optimizer/src/filter_push_down.rs
index 96abdc4c5..8d2d9c06d 100644
--- a/datafusion/optimizer/src/filter_push_down.rs
+++ b/datafusion/optimizer/src/filter_push_down.rs
@@ -1825,7 +1825,7 @@ mod tests {
 
         let expected ="Projection: #a, #b\
             \n  Filter: #a = Int64(10) AND #b > Int64(11)\
-            \n    TableScan: test projection=Some([0]), partial_filters=[#a = Int64(10), #b > Int64(11)]";
+            \n    TableScan: test projection=Some([a]), partial_filters=[#a = Int64(10), #b > Int64(11)]";
 
         assert_optimized_plan_eq(&plan, expected);
 
diff --git a/datafusion/optimizer/src/projection_push_down.rs b/datafusion/optimizer/src/projection_push_down.rs
index cd26d886c..c6c81fd1f 100644
--- a/datafusion/optimizer/src/projection_push_down.rs
+++ b/datafusion/optimizer/src/projection_push_down.rs
@@ -549,7 +549,7 @@ mod tests {
             .build()?;
 
         let expected = "Aggregate: groupBy=[[]], aggr=[[MAX(#test.b)]]\
-        \n  TableScan: test projection=Some([1])";
+        \n  TableScan: test projection=Some([b])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -565,7 +565,7 @@ mod tests {
             .build()?;
 
         let expected = "Aggregate: groupBy=[[#test.c]], aggr=[[MAX(#test.b)]]\
-        \n  TableScan: test projection=Some([1, 2])";
+        \n  TableScan: test projection=Some([b, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -583,7 +583,7 @@ mod tests {
 
         let expected = "Aggregate: groupBy=[[#a.c]], aggr=[[MAX(#a.b)]]\
         \n  SubqueryAlias: a\
-        \n    TableScan: test projection=Some([1, 2])";
+        \n    TableScan: test projection=Some([b, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -601,7 +601,7 @@ mod tests {
 
         let expected = "Aggregate: groupBy=[[]], aggr=[[MAX(#test.b)]]\
         \n  Filter: #test.c\
-        \n    TableScan: test projection=Some([1, 2])";
+        \n    TableScan: test projection=Some([b, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -617,7 +617,7 @@ mod tests {
             .project(vec![col("a"), col("c"), col("b")])?
             .build()?;
         let expected = "Projection: #test.a, #test.c, #test.b\
-        \n  TableScan: test projection=Some([0, 1, 2])";
+        \n  TableScan: test projection=Some([a, b, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -632,7 +632,7 @@ mod tests {
             .project(vec![col("c"), col("b"), col("a")])?
             .build()?;
         let expected = "Projection: #test.c, #test.b, #test.a\
-        \n  TableScan: test projection=Some([0, 1, 2])";
+        \n  TableScan: test projection=Some([a, b, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -655,7 +655,7 @@ mod tests {
         \n  Filter: #test.a > Int32(1)\
         \n    Filter: #test.b > Int32(1)\
         \n      Filter: #test.c > Int32(1)\
-        \n        TableScan: test projection=Some([0, 1, 2])";
+        \n        TableScan: test projection=Some([a, b, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -677,8 +677,8 @@ mod tests {
         // make sure projections are pushed down to both table scans
         let expected = "Projection: #test.a, #test.b, #test2.c1\
         \n  Left Join: #test.a = #test2.c1\
-        \n    TableScan: test projection=Some([0, 1])\
-        \n    TableScan: test2 projection=Some([0])";
+        \n    TableScan: test projection=Some([a, b])\
+        \n    TableScan: test2 projection=Some([c1])";
 
         let optimized_plan = optimize(&plan)?;
         let formatted_plan = format!("{:?}", optimized_plan);
@@ -720,8 +720,8 @@ mod tests {
         // make sure projections are pushed down to both table scans
         let expected = "Projection: #test.a, #test.b\
         \n  Left Join: #test.a = #test2.c1\
-        \n    TableScan: test projection=Some([0, 1])\
-        \n    TableScan: test2 projection=Some([0])";
+        \n    TableScan: test projection=Some([a, b])\
+        \n    TableScan: test2 projection=Some([c1])";
 
         let optimized_plan = optimize(&plan)?;
         let formatted_plan = format!("{:?}", optimized_plan);
@@ -761,8 +761,8 @@ mod tests {
         // make sure projections are pushed down to table scan
         let expected = "Projection: #test.a, #test.b\
         \n  Left Join: Using #test.a = #test2.a\
-        \n    TableScan: test projection=Some([0, 1])\
-        \n    TableScan: test2 projection=Some([0])";
+        \n    TableScan: test projection=Some([a, b])\
+        \n    TableScan: test2 projection=Some([a])";
 
         let optimized_plan = optimize(&plan)?;
         let formatted_plan = format!("{:?}", optimized_plan);
@@ -797,7 +797,7 @@ mod tests {
             .build()?;
 
         let expected = "Projection: CAST(#test.c AS Float64)\
-        \n  TableScan: test projection=Some([2])";
+        \n  TableScan: test projection=Some([c])";
 
         assert_optimized_plan_eq(&projection, expected);
 
@@ -817,7 +817,7 @@ mod tests {
         assert_fields_eq(&plan, vec!["a", "b"]);
 
         let expected = "Projection: #test.a, #test.b\
-        \n  TableScan: test projection=Some([0, 1])";
+        \n  TableScan: test projection=Some([a, b])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -851,7 +851,7 @@ mod tests {
         assert_fields_eq(&plan, vec!["a", "b"]);
 
         let expected = "Projection: #a, #b\
-        \n  TableScan: test projection=Some([0, 1])";
+        \n  TableScan: test projection=Some([a, b])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -873,7 +873,7 @@ mod tests {
 
         let expected = "Limit: 5\
         \n  Projection: #test.c, #test.a\
-        \n    TableScan: test projection=Some([0, 2])";
+        \n    TableScan: test projection=Some([a, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -885,7 +885,7 @@ mod tests {
         let table_scan = test_table_scan()?;
         let plan = LogicalPlanBuilder::from(table_scan).build()?;
         // should expand projection to all columns without projection
-        let expected = "TableScan: test projection=Some([0, 1, 2])";
+        let expected = "TableScan: test projection=Some([a, b, c])";
         assert_optimized_plan_eq(&plan, expected);
         Ok(())
     }
@@ -897,7 +897,7 @@ mod tests {
             .project(vec![lit(1_i64), lit(2_i64)])?
             .build()?;
         let expected = "Projection: Int64(1), Int64(2)\
-                      \n  TableScan: test projection=Some([0])";
+                      \n  TableScan: test projection=Some([a])";
         assert_optimized_plan_eq(&plan, expected);
         Ok(())
     }
@@ -922,7 +922,7 @@ mod tests {
         Aggregate: groupBy=[[#test.c]], aggr=[[MAX(#test.a)]]\
         \n  Filter: #test.c > Int32(1)\
         \n    Projection: #test.c, #test.a\
-        \n      TableScan: test projection=Some([0, 2])";
+        \n      TableScan: test projection=Some([a, c])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -946,7 +946,7 @@ mod tests {
 
         let expected = "\
         Projection: Int32(1) AS a\
-        \n  TableScan: test projection=Some([0])";
+        \n  TableScan: test projection=Some([a])";
 
         assert_optimized_plan_eq(&plan, expected);
 
@@ -992,7 +992,7 @@ mod tests {
         let expected = "Projection: #test.c, #test.a, #MAX(test.b)\
         \n  Filter: #test.c > Int32(1)\
         \n    Aggregate: groupBy=[[#test.a, #test.c]], aggr=[[MAX(#test.b)]]\
-        \n      TableScan: test projection=Some([0, 1, 2])";
+        \n      TableScan: test projection=Some([a, b, c])";
 
         assert_optimized_plan_eq(&plan, expected);