diff --git a/verticapy/__init__.py b/verticapy/__init__.py
index 9d7d1a4c6..40b28dbf0 100755
--- a/verticapy/__init__.py
+++ b/verticapy/__init__.py
@@ -38,7 +38,7 @@
__license__: str = "Apache License, Version 2.0"
__version__: str = "1.0.5"
__iteration__: int = 1
-__date__: str = "20092024"
+__date__: str = "25092024"
__last_commit__: str = "d15329cab9a2360454f4473e676068d2f793b965"
__long_version__: str = f"{__version__}-{__iteration__}—{__date__}-{__last_commit__}"
__codecov__: float = 0.84
diff --git a/verticapy/performance/vertica/qprof.py b/verticapy/performance/vertica/qprof.py
index a289f68d0..da7a88488 100755
--- a/verticapy/performance/vertica/qprof.py
+++ b/verticapy/performance/vertica/qprof.py
@@ -1223,6 +1223,10 @@ def __init__(
else:
self.statement_id = 1
+ # To store metrics and not recompute them.
+ self.transaction_all_metrics = {}
+ self.transaction_tr_order_all = {}
+
# BUILDING THE target_schema.
if target_schema == "v_temp_schema":
self.target_schema = self._v_temp_schema_dict()
@@ -2746,6 +2750,9 @@ def _get_qplan_tr_order(
For more details, please look at
:py:class:`~verticapy.performance.vertica.qprof.QueryProfiler`.
"""
+ current_tuple = (self.transaction_id, self.statement_id)
+ if current_tuple in self.transaction_tr_order_all:
+ return self.transaction_tr_order_all[current_tuple]
query = f"""
SELECT
REGEXP_SUBSTR(step_label, '\\d+')::INT
@@ -2763,16 +2770,26 @@ def _get_qplan_tr_order(
title="Getting the corresponding query",
method="fetchall",
)
- return list(dict.fromkeys([q[0] for q in res]))
+ res = list(dict.fromkeys([q[0] for q in res]))
except:
- return []
+ res = []
+
+ # Storing the metrics.
+ self.transaction_tr_order_all[current_tuple] = res
+
+ return res
def _get_metric_val(self):
"""
Helper function to returns the
operator statistics.
"""
- # Init
+ # If stored, we return the value.
+ current_tuple = (self.transaction_id, self.statement_id)
+ if current_tuple in self.transaction_all_metrics:
+ return self.transaction_all_metrics[current_tuple]
+
+ # Init.
query = self.get_qexecution_report(granularity=1, genSQL=True)
cols = self.get_qexecution_report(return_cols=True)
res = _executeSQL(
@@ -2797,7 +2814,7 @@ def _get_metric_val(self):
current_metric = -1
metric_value_op[me[0]][me[2]][col] = current_metric
- # Summary
+ # Summary.
query = self.get_qexecution_report(granularity=2, genSQL=True)
res = _executeSQL(
query,
@@ -2819,6 +2836,10 @@ def _get_metric_val(self):
current_metric = -1
metric_value[col][me[0]] = current_metric
+ # Storing the metrics.
+ self.transaction_all_metrics[current_tuple] = metric_value_op, metric_value
+
+ # Returning the metric.
return metric_value_op, metric_value
def _get_vdf_summary(self):
@@ -3202,6 +3223,26 @@ def get_qplan_tree(
NULL values.
Default: '#EFEFEF' (light
gray)
+ - threshold_metric1:
+ Threshold used to disable
+ some specific ``path_id``
+ based on the first metric.
+ If the ``path_id`` value
+ is under this value: A
+ minimalist representation
+ of the corresponding
+ ``path_id`` will be used.
+ Default: None
+ - threshold_metric2:
+ Threshold used to disable
+ some specific ``path_id``
+ based on the first metric.
+ If the ``path_id`` value
+ is under this value: A
+ minimalist representation
+ of the corresponding
+ ``path_id`` will be used.
+ Default: None
- fontcolor:
Font color.
Default (light-m): #000000 (black)
diff --git a/verticapy/performance/vertica/tree.py b/verticapy/performance/vertica/tree.py
index 82e1e938f..62dd16792 100644
--- a/verticapy/performance/vertica/tree.py
+++ b/verticapy/performance/vertica/tree.py
@@ -347,6 +347,10 @@ def _set_style(self, d: dict) -> None:
d["legend2_max"] = 0
else:
d["legend2_max"] += 1
+ if "threshold_metric1" not in d:
+ d["threshold_metric1"] = None
+ if "threshold_metric2" not in d:
+ d["threshold_metric2"] = None
if "display_path_transition" not in d:
d["display_path_transition"] = True
if "display_annotations" not in d:
@@ -1458,6 +1462,7 @@ def _gen_label_table(
label: Union[int, str],
colors: list,
operator: Optional[str] = None,
+ legend_metrics: Optional[list] = None,
) -> str:
"""
Generates the Graphviz
@@ -1485,16 +1490,59 @@ def _gen_label_table(
See :py:meth:`~verticapy.performance.vertica.tree`
for more information.
"""
- if isinstance(label, int) and label < 0:
- label = self._get_special_operator(operator)
- if not (self.style["display_operator"]) and len(colors) == 1:
- return f'"{label}", style="filled", fillcolor="{colors[0]}"'
+
+ # Init.
fontcolor = self.style["fontcolor"]
fontsize = self.style["fontsize"]
fillcolor = self.style["fillcolor"]
width = self.style["width"] * 30
height = self.style["height"] * 60
operator_icon = self._get_operator_icon(operator)
+
+ # Getting the label.
+ if isinstance(label, int) and label < 0:
+ label = self._get_special_operator(operator)
+
+ # Metrics Init.
+ display_path_id = True
+
+ if isinstance(legend_metrics, list) and len(legend_metrics) > 0:
+ metric_1 = legend_metrics[0]
+ else:
+ metric_1 = None
+ if isinstance(legend_metrics, list) and len(legend_metrics) > 1:
+ metric_2 = legend_metrics[1]
+ else:
+ metric_2 = None
+
+ metric_1_t = self.style["threshold_metric1"]
+ metric_2_t = self.style["threshold_metric2"]
+
+ if not (isinstance(metric_1_t, NoneType)):
+ if isinstance(metric_1, NoneType) or metric_1 < metric_1_t:
+ display_path_id = False
+
+ if not (isinstance(metric_2_t, NoneType)):
+ if isinstance(metric_2, NoneType) or metric_2 < metric_2_t:
+ display_path_id = False
+
+ # Special Display.
+ if not (display_path_id):
+ return (
+ '<
>",
+ display_path_id,
+ )
+ if not (self.style["display_operator"]) and len(colors) == 1:
+ return (
+ f'"{label}", style="filled", fillcolor="{colors[0]}"',
+ display_path_id,
+ )
+
+ # Main.
if len(colors) > 1:
second_color = (
f'{label} | {operator_icon}{second_color}'
f"{proj}>"
)
- return label
+ return label, display_path_id
def _gen_labels(self) -> str:
"""
@@ -1710,6 +1758,7 @@ def _gen_labels(self) -> str:
tooltip_metrics += me_description
colors = [color]
+ legend_metrics = [self._get_metric(self.rows[i], self.metric[0], i)]
if len(self.metric) > 1:
if not (isinstance(self.metric[1], NoneType)):
if all_metrics_2[i] >= 0:
@@ -1723,10 +1772,12 @@ def _gen_labels(self) -> str:
self.style["hasnull_1"] = True
else:
colors += [self.style["fillcolor"]]
- label = self._gen_label_table(
+ legend_metrics += [self._get_metric(self.rows[i], self.metric[1], i)]
+ label, display_path_id = self._gen_label_table(
label,
colors,
operator=row,
+ legend_metrics=legend_metrics,
)
if tree_id in links and display_tr:
@@ -1739,6 +1790,8 @@ def _gen_labels(self) -> str:
if ns_icon != "":
ns_icon += " "
ns_icon += QprofUtility._get_execute_on(tooltip)
+ if not (display_path_id):
+ ns_icon = ""
# Final Tooltip.
description = "\n\nDescriptors\n------------\n" + "\n".join(
tooltip.split("\n")[1:]
@@ -1957,6 +2010,9 @@ def _gen_legend_annotations(self, rows: Optional[list] = None):
all_legend[
"BROADCAST"
] = f'B | BROADCAST |
'
+ all_legend[
+ "..."
+ ] = f'... | BROADCAST |
'
if "GLOBAL RESEGMENT" in row_tmp and "LOCAL RESEGMENT" in row_tmp:
all_legend[
"GLR"
@@ -1973,6 +2029,10 @@ def _gen_legend_annotations(self, rows: Optional[list] = None):
all_legend[
"RESEGMENT"
] = f'R | RESEGMENT |
'
+ if "RESEGMENT" in row_tmp and "BROADCAST" not in row_tmp:
+ all_legend[
+ "---"
+ ] = f'--- | RESEGMENT | NO BROADCAST |
'
if "HASH" in row_tmp:
all_legend[
"HASH"
@@ -1998,14 +2058,51 @@ def _gen_legend_annotations(self, rows: Optional[list] = None):
"ALL NODES"
] = f'🌐 | ALL NODES |
'
+ trans_sort = [
+ "CROSS JOIN",
+ "INNER",
+ "OUTER",
+ "MERGE",
+ "FILTER",
+ "PIPELINED",
+ "BROADCAST",
+ "GLR",
+ "GR",
+ "LR",
+ "RESEGMENT",
+ ]
+ trans_links_sort = [
+ "...",
+ "---",
+ ]
+ trans_info_sort = [
+ "NO STATISTICS",
+ "QUERY INITIATOR",
+ "ALL NODES",
+ ]
+
res = ""
- for op in all_legend:
- res += all_legend[op]
+ for idx, trans_list in enumerate(
+ [trans_sort, trans_links_sort, trans_info_sort]
+ ):
+ res_trans = ""
+ if idx == 0:
+ name_tmp = "Path transition"
+ elif idx == 1:
+ name_tmp = "Link"
+ elif idx == 2:
+ name_tmp = "Information"
+ for op in trans_list:
+ if op in all_legend:
+ res_trans += all_legend[op]
+ if res_trans:
+ res += (
+ f' | {name_tmp} |
'
+ + res_trans
+ )
if res:
- res_f = f'\tlegend_annotations [shape=plaintext, fillcolor=white, label=<'
- res = f'{res_f} | Path transition |
{res}'
- res += "
>]\n\n"
+ res = f'\tlegend_annotations [shape=plaintext, fillcolor=white, label=<>]\n\n'
return res
def _gen_legend(self, metric: Optional[list] = None, idx: int = 0) -> str: