feat: tool to graphically display plans (#803)
* feat: tool to graphically display plans * docs: Add note to CONTRIBUTING.md Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>pull/24376/head
parent
0fe590cedd
commit
da39e4099c
|
@ -118,6 +118,44 @@ can use all the features of that crate. For example, to disable the
|
|||
RUST_LOG=debug,hyper::proto::h1=info,h2=info cargo test --workspace
|
||||
```
|
||||
|
||||
### Visually showing explain plans
|
||||
|
||||
Some query plans are output in the log in [graphviz](https://graphviz.org/) format. To display them you can use the `tools/iplan` helper.
|
||||
|
||||
For example, if you want to display this plan:
|
||||
|
||||
```
|
||||
// Begin DataFusion GraphViz Plan (see https://graphviz.org)
|
||||
digraph {
|
||||
subgraph cluster_1
|
||||
{
|
||||
graph[label="LogicalPlan"]
|
||||
2[shape=box label="SchemaPivot"]
|
||||
3[shape=box label="Projection: "]
|
||||
2 -> 3 [arrowhead=none, arrowtail=normal, dir=back]
|
||||
4[shape=box label="Filter: Int64(0) LtEq #time And #time Lt Int64(10000) And #host Eq Utf8(_server01_)"]
|
||||
3 -> 4 [arrowhead=none, arrowtail=normal, dir=back]
|
||||
5[shape=box label="TableScan: attributes projection=None"]
|
||||
4 -> 5 [arrowhead=none, arrowtail=normal, dir=back]
|
||||
}
|
||||
subgraph cluster_6
|
||||
{
|
||||
graph[label="Detailed LogicalPlan"]
|
||||
7[shape=box label="SchemaPivot\nSchema: [non_null_column:Utf8]"]
|
||||
8[shape=box label="Projection: \nSchema: []"]
|
||||
7 -> 8 [arrowhead=none, arrowtail=normal, dir=back]
|
||||
9[shape=box label="Filter: Int64(0) LtEq #time And #time Lt Int64(10000) And #host Eq Utf8(_server01_)\nSchema: [color:Utf8;N, time:Int64]"]
|
||||
8 -> 9 [arrowhead=none, arrowtail=normal, dir=back]
|
||||
10[shape=box label="TableScan: attributes projection=None\nSchema: [color:Utf8;N, time:Int64]"]
|
||||
9 -> 10 [arrowhead=none, arrowtail=normal, dir=back]
|
||||
}
|
||||
}
|
||||
// End DataFusion GraphViz Plan
|
||||
```
|
||||
|
||||
You can pipe it to `iplan` and render as a .pdf
|
||||
|
||||
|
||||
## Running `rustfmt` and `clippy`
|
||||
|
||||
CI will check the code formatting with [`rustfmt`] and Rust best practices with [`clippy`].
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# This script extracts all plans from its stdin, invokes dot on them
|
||||
# to make a multi-page pdf / open to display them
|
||||
#
|
||||
import os
|
||||
import fileinput
|
||||
|
||||
files = []
|
||||
|
||||
in_graphviz = False
|
||||
|
||||
# Note we combine multiple digraphs
|
||||
for line in fileinput.input():
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith("// Begin DataFusion GraphViz Plan"):
|
||||
filename = "/tmp/plan{}.ps".format(len(files))
|
||||
files.append(filename)
|
||||
f = open(filename, "w")
|
||||
in_graphviz = True
|
||||
|
||||
if in_graphviz:
|
||||
f.write(line)
|
||||
f.write("\n")
|
||||
|
||||
if line.startswith("// End DataFusion GraphViz Plan"):
|
||||
in_graphviz = False
|
||||
f = None
|
||||
|
||||
# try to ensure any open is closed
|
||||
f = None
|
||||
|
||||
|
||||
# TODO make this not mac specific
|
||||
if len(files) > 0:
|
||||
#print("Found files: {}".format(files))
|
||||
print("Found {} graphs, converting to ps".format(len(files)))
|
||||
# convert them to ps files
|
||||
ps_files = []
|
||||
for file in files:
|
||||
output_file = "{}.pdf".format(file)
|
||||
os.system("dot -Tpdf < {} > {}.pdf".format(file, output_file))
|
||||
ps_files.append(output_file)
|
||||
|
||||
# combine all the postscript files together
|
||||
cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=/tmp/plan.pdf {}".format(" ".join(ps_files))
|
||||
|
||||
print("Running command:", cmd)
|
||||
os.system(cmd)
|
||||
|
||||
print("Opening with system viewer")
|
||||
os.system('open /tmp/plan.pdf')
|
Loading…
Reference in New Issue