Skip to content
Permalink
Browse files

Render plan structure

Make the tree structure of the plan clearer. Sample output:

                                               Query Plan
---------------------------------------------------------------------------------------------------------
 Output[_col0]
 │   Layout: [count:bigint]
 │   Estimates: {rows: ? (?), cpu: ?, memory: ?, network: ?}
 │   _col0 := count
 └─ Aggregate(FINAL)
    │   Layout: [count:bigint]
    │   Estimates: {rows: ? (?), cpu: ?, memory: ?, network: ?}
    │   count := "count"("count_9")
    └─ LocalExchange[SINGLE] ()
       │   Layout: [count_9:bigint]
       │   Estimates: {rows: ? (?), cpu: ?, memory: ?, network: ?}
       └─ RemoteExchange[GATHER]
          │   Layout: [count_9:bigint]
          │   Estimates: {rows: ? (?), cpu: ?, memory: ?, network: ?}
          └─ Aggregate(PARTIAL)
             │   Layout: [count_9:bigint]
             │   count_9 := "count"(*)
             └─ InnerJoin[("orderkey" = "orderkey_0")]
                │   Layout: []
                │   Estimates: {rows: 60175 (0B), cpu: 2.32M, memory: 528.88kB, network: 528.88kB}
                │   Distribution: PARTITIONED
                ├─ TableScan[tpch:orders:sf0.01]
                │      Layout: [orderkey:bigint]
                │      Estimates: {rows: 15000 (131.84kB), cpu: 131.84k, memory: 0B, network: 0B}
                │      orderkey := tpch:orderkey
                │      tpch:orderstatus
                │          :: [[F], [O], [P]]
                └─ LocalExchange[HASH] ("orderkey_0")
                   │   Layout: [orderkey_0:bigint]
                   │   Estimates: {rows: 60175 (528.88kB), cpu: 1.55M, memory: 0B, network: 528.88kB}
                   └─ RemoteExchange[REPARTITION]
                      │   Layout: [orderkey_0:bigint]
                      │   Estimates: {rows: 60175 (528.88kB), cpu: 1.03M, memory: 0B, network: 528.88kB}
                      └─ TableScan[tpch:lineitem:sf0.01]
                             Layout: [orderkey_0:bigint]
                             Estimates: {rows: 60175 (528.88kB), cpu: 528.88k, memory: 0B, network: 0B}
                             orderkey_0 := tpch:orderkey
  • Loading branch information...
martint committed Jun 2, 2019
1 parent 6651ea4 commit 1e5ca439debb0ca7d9de06329938aa81277fff72
Showing with 84 additions and 12 deletions.
  1. +84 −12 presto-main/src/main/java/io/prestosql/sql/planner/planprinter/TextRenderer.java
@@ -21,12 +21,14 @@
import io.prestosql.sql.planner.Symbol;
import io.prestosql.sql.planner.planprinter.NodeRepresentation.TypedSymbol;

import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
import static io.airlift.units.DataSize.Unit.BYTE;
import static java.lang.Double.NEGATIVE_INFINITY;
@@ -54,13 +56,13 @@ public TextRenderer(boolean verbose, int level)
public String render(PlanRepresentation plan)
{
StringBuilder output = new StringBuilder();
return writeTextOutput(output, plan, level, plan.getRoot());
NodeRepresentation root = plan.getRoot();
return writeTextOutput(output, plan, Indent.newInstance(!root.getChildren().isEmpty()), root);
}

private String writeTextOutput(StringBuilder output, PlanRepresentation plan, int level, NodeRepresentation node)
private String writeTextOutput(StringBuilder output, PlanRepresentation plan, Indent indent, NodeRepresentation node)
{
output.append(indentString(level))
.append("- ")
output.append(indent.nodeIndent())
.append(node.getName())
.append(node.getIdentifier())
.append("\n");
@@ -69,20 +71,20 @@ private String writeTextOutput(StringBuilder output, PlanRepresentation plan, in
.map(s -> s.getSymbol() + ":" + s.getType())
.collect(joining(", "));

output.append(indentMultilineString("Layout: [" + columns + "]\n", level + 2));
output.append(indentMultilineString("Layout: [" + columns + "]\n", indent.detailIndent()));

String estimates = printEstimates(plan, node);
if (!estimates.isEmpty()) {
output.append(indentMultilineString(estimates, level + 2));
output.append(indentMultilineString(estimates, indent.detailIndent()));
}

String stats = printStats(plan, node);
if (!stats.isEmpty()) {
output.append(indentMultilineString(stats, level + 2));
output.append(indentMultilineString(stats, indent.detailIndent()));
}

if (!node.getDetails().isEmpty()) {
String details = indentMultilineString(node.getDetails(), level + 2);
String details = indentMultilineString(node.getDetails(), indent.detailIndent());
output.append(details);
if (!details.endsWith("\n")) {
output.append('\n');
@@ -95,8 +97,15 @@ private String writeTextOutput(StringBuilder output, PlanRepresentation plan, in
.map(Optional::get)
.collect(toList());

for (NodeRepresentation child : children) {
writeTextOutput(output, plan, level + 1, child);
for (Iterator<NodeRepresentation> iterator = children.iterator(); iterator.hasNext(); ) {
NodeRepresentation child = iterator.next();

boolean hasChildren = child.getChildren().stream()
.map(plan::getNode)
.filter(Optional::isPresent)
.count() > 0;

writeTextOutput(output, plan, indent.forChild(!iterator.hasNext(), hasChildren), child);
}

return output.toString();
@@ -294,8 +303,71 @@ static String indentString(int indent)
return Strings.repeat(" ", indent);
}

private static String indentMultilineString(String string, int level)
private static String indentMultilineString(String string, String indent)
{
return string.replaceAll("(?m)^", indentString(level));
return string.replaceAll("(?m)^", indent);
}

private static class Indent
{
private static final String VERTICAL_LINE = "\u2502";
private static final String LAST_NODE = "\u2514\u2500";
private static final String INTERMEDIATE_NODE = "\u251c\u2500";

private final String firstLinePrefix;
private final String nextLinesPrefix;
private final boolean hasChildren;

public static Indent newInstance(boolean hasChildren)
{
return new Indent("", "", hasChildren);
}

private Indent(String firstLinePrefix, String nextLinesPrefix, boolean hasChildren)
{
this.firstLinePrefix = firstLinePrefix;
this.nextLinesPrefix = nextLinesPrefix;
this.hasChildren = hasChildren;
}

public Indent forChild(boolean last, boolean hasChildren)
{
String first;
String next;

if (last) {
first = pad(LAST_NODE, 3);
next = pad("", 3);
}
else {
first = pad(INTERMEDIATE_NODE, 3);
next = pad(VERTICAL_LINE, 3);
}

return new Indent(nextLinesPrefix + first, nextLinesPrefix + next, hasChildren);
}

public String nodeIndent()
{
return firstLinePrefix;
}

public String detailIndent()
{
String indent = "";

if (hasChildren) {
indent = VERTICAL_LINE;
}

return nextLinesPrefix + pad(indent, 4);
}

private static String pad(String text, int length)
{
checkArgument(text.length() <= length, "text is longer that length");

return text + Strings.repeat(" ", length - text.length());
}
}
}

0 comments on commit 1e5ca43

Please sign in to comment.
You can’t perform that action at this time.