"Append":"Used in a UNION to merge multiple record sets by appending them together.",
"Limit":"Returns a specified number of rows from a record set.",
"Sort":"Sorts a record set based on the specified sort key.",
"Nested Loop":"Merges two record sets by looping through every record in the first set and trying to find a match in the second set. All matching records are returned.",
"Merge Join":"Merges two record sets by first sorting them on a join key.",
"Hash":"Generates a hash table from the records in the input recordset. Hash is used by Hash Join.",
"Hash Join":"Joins to record sets by hashing one of them (using a Hash Scan).",
"Aggregate":"Groups records together based on a GROUP BY or aggregate function (e.g. sum()).",
"Hashaggregate":"Groups records together based on a GROUP BY or aggregate function (e.g. sum()). Hash Aggregate uses a hash to first organize the records by a key.",
"Sequence Scan":"Finds relevant records by sequentially scanning the input record set. When reading from a table, Seq Scans (unlike Index Scans) perform a single read operation (only the table is read).",
"Seq Scan":"Finds relevant records by sequentially scanning the input record set. When reading from a table, Seq Scans (unlike Index Scans) perform a single read operation (only the table is read).",
"Index Scan":"Finds relevant records based on an Index. Index Scans perform 2 read operations: one to read the index and another to read the actual value from the table.",
"Index Only Scan":"Finds relevant records based on an Index. Index Only Scans perform a single read operation from the index and do not read from the corresponding table.",
"Bitmap Heap Scan":"Searches through the pages returned by the Bitmap Index Scan for relevant rows.",
"Bitmap Index Scan":"Uses a Bitmap Index (index which uses 1 bit per page) to find all relevant pages. Results of this node are fed to the Bitmap Heap Scan.",
"CTEScan":"Performs a sequential scan of Common Table Expression (CTE) query results. Note that results of a CTE are materialized (calculated and temporarily stored).",
"ProjectSet":"ProjectSet appears when the SELECT or ORDER BY clause of the query. They basically just execute the set-returning function(s) for each tuple until none of the functions return any more records.",
"Result":"Returns result",
}
classVisualizer:
def__init__(self,terminal_width=100,color=True):
self.color=color
self.terminal_width=terminal_width
self.string_lines=[]
defload(self,explain_dict):
self.plan=explain_dict.pop("Plan")
self.explain=explain_dict
self.process_all()
self.generate_lines()
defprocess_all(self):
self.plan=self.process_plan(self.plan)
self.plan=self.calculate_outlier_nodes(self.plan)
#
defprocess_plan(self,plan):
plan=self.calculate_planner_estimate(plan)
plan=self.calculate_actuals(plan)
self.calculate_maximums(plan)
#
forindexinrange(len(plan.get("Plans",[]))):
_plan=plan["Plans"][index]
plan["Plans"][index]=self.process_plan(_plan)
returnplan
defprefix_format(self,v):
ifself.color:
returncolor(v,fg="bright_black")
returnv
deftag_format(self,v):
ifself.color:
returncolor(v,fg="white",bg="red")
returnv
defmuted_format(self,v):
ifself.color:
returncolor(v,fg="bright_black")
returnv
defbold_format(self,v):
ifself.color:
returncolor(v,fg="white")
returnv
defgood_format(self,v):
ifself.color:
returncolor(v,fg="green")
returnv
defwarning_format(self,v):
ifself.color:
returncolor(v,fg="yellow")
returnv
defcritical_format(self,v):
ifself.color:
returncolor(v,fg="red")
returnv
defoutput_format(self,v):
ifself.color:
returncolor(v,fg="cyan")
returnv
defcalculate_planner_estimate(self,plan):
plan["Planner Row Estimate Factor"]=0
plan["Planner Row Estimate Direction"]="Under"
ifplan["Plan Rows"]==plan["Actual Rows"]:
returnplan
ifplan["Plan Rows"]!=0:
plan["Planner Row Estimate Factor"]=(
plan["Actual Rows"]/plan["Plan Rows"]
)
ifplan["Planner Row Estimate Factor"]<10:
plan["Planner Row Estimate Factor"]=0
plan["Planner Row Estimate Direction"]="Over"
ifplan["Actual Rows"]!=0:
plan["Planner Row Estimate Factor"]=(
plan["Plan Rows"]/plan["Actual Rows"]
)
returnplan
#
defcalculate_actuals(self,plan):
plan["Actual Duration"]=plan["Actual Total Time"]
plan["Actual Cost"]=plan["Total Cost"]
forchildinplan.get("Plans",[]):
ifchild["Node Type"]!="CTEScan":
plan["Actual Duration"]=(
plan["Actual Duration"]-child["Actual Total Time"]