-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnormalize.py
More file actions
87 lines (70 loc) · 1.98 KB
/
Copy pathnormalize.py
File metadata and controls
87 lines (70 loc) · 1.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# normalize.py
from typing import Any, Dict
DENY_KEYS = {
# execution / timing
"Actual Startup Time",
"Actual Total Time",
"Actual Rows",
"Actual Loops",
"Execution Time",
"Planning Time",
# cost estimates
"Startup Cost",
"Total Cost",
"Plan Rows",
"Plan Width",
# buffers / IO
"Shared Hit Blocks",
"Shared Read Blocks",
"Shared Dirtied Blocks",
"Shared Written Blocks",
"Local Hit Blocks",
"Local Read Blocks",
"Local Dirtied Blocks",
"Local Written Blocks",
"Temp Read Blocks",
"Temp Written Blocks",
# parallel / runtime
"Workers",
"Workers Planned",
"Workers Launched",
"Peak Memory Usage",
"Disk Usage",
"HashAgg Batches",
"Batches",
# misc
"Async Capable",
"Parent Relationship",
"Filters",
"filter",
"Rows Removed by Filter",
}
def normalize_plan(plan_json: dict) -> dict:
"""
Normalize a PostgreSQL EXPLAIN (FORMAT JSON) plan into a
canonical, execution-invariant tree.
"""
# Handle string input (text EXPLAIN output, not JSON format)
if isinstance(plan_json, str):
return {"_raw_text": plan_json, "_format": "text"}
# unwrap EXPLAIN's list wrapper
if isinstance(plan_json, list):
plan_json = plan_json[0]
# Handle case where unwrapped list item is a string
if isinstance(plan_json, str):
return {"_raw_text": plan_json, "_format": "text"}
# unwrap top-level Plan
node = plan_json["Plan"] if "Plan" in plan_json else plan_json
def normalize_node(node: Dict[str, Any]) -> Dict[str, Any]:
normalized = {}
for key, value in node.items():
if key in DENY_KEYS:
continue
if key == "Plans":
normalized["Plans"] = [
normalize_node(child) for child in value
]
else:
normalized[key] = value
return normalized
return normalize_node(node)