# `plananalyze`
# PostgreSQL `EXPLAIN` Plan Analyzer - Extract insights from execution plans Query
## For best results, run `EXPLAIN` like so `EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)`
``
# Quickstart
1. Run "ANALYZE" on your Query
2. Copy-paste output from PostgreSQL
3. Review details :)
```python
from plananalyze import analyze_plan
plan = """
Hash Join (cost=12.70..30.50 rows=120 width=743)
Hash Cond: ((d.name)::text = (employees.department)::text)
-> Seq Scan on departments d (cost=0.00..14.80 rows=480 width=142)
-> Hash (cost=11.20..11.20 rows=120 width=601)
-> Seq Scan on employees (cost=0.00..11.20 rows=120 width=601)
"""
result = analyze_plan(plan, format_type="summary")
print(result)
```
Output:
```shell
📊 EXECUTION OVERVIEW:
Total Cost: 30.50
Node Count: 5
🔍 OPERATIONS:
Sequential Scans: 2
Index Scans: 0
Joins: 1
Sorts: 0
```
# Detailed Response
```python
# Use format_type="detailed"
result = analyze_plan(plan, format_type="detailed")
```
Output:
```shell
📈 EXECUTION METRICS:
Total Cost: 30.50
Root Operation: Hash Join
🏗️ PLAN STRUCTURE:
Total Nodes: 5
Plan Depth: 0
🔍 OPERATION BREAKDOWN:
Sequential Scans: 2
Index Scans: 0
Index Only Scans: 0
Bitmap Scans: 0
Join Operations: 1
Sort Operations: 0
Hash Operations: 2
Aggregate Operations: 0
💰 MOST EXPENSIVE OPERATIONS:
1. Hash Join - Cost: 30.50 (100.0%)
2. -> Seq Scan on departments - Cost: 14.80 (48.5%)
3. -> Hash - Cost: 11.20 (36.7%)
```
# JSON output
```python
# Use format_type="json"
result = analyze_plan(plan, format_type="json")
```
# JSON Input
### Run "explain" on PostgreSQL query using `EXPLAIN (FORMAT JSON)`
```python
from plananalyze import analyze_plan
plan_json = """
[
{
"Plan": {
"Node Type": "Hash Join",
"Parallel Aware": false,
"Async Capable": false,
"Join Type": "Inner",
"Startup Cost": 12.70,
"Total Cost": 30.50,
"Plan Rows": 120,
"Plan Width": 743,
"Inner Unique": false,
"Hash Cond": "((d.name)::text = (employees.department)::text)",
"Plans": [
{
"Node Type": "Seq Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Relation Name": "departments",
"Alias": "d",
"Startup Cost": 0.00,
"Total Cost": 14.80,
"Plan Rows": 480,
"Plan Width": 142
},
{
"Node Type": "Hash",
"Parent Relationship": "Inner",
"Parallel Aware": false,
"Async Capable": false,
"Startup Cost": 11.20,
"Total Cost": 11.20,
"Plan Rows": 120,
"Plan Width": 601,
"Plans": [
{
"Node Type": "Seq Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Relation Name": "employees",
"Alias": "employees",
"Startup Cost": 0.00,
"Total Cost": 11.20,
"Plan Rows": 120,
"Plan Width": 601
}
]
}
]
}
}
]
"""
result = analyze_plan(plan_json, format_type="summary")
print(result)
```
Raw data
{
"_id": null,
"home_page": "https://github.com/GujaLomsadze/PlanAnalyzer",
"name": "plananalyze",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "postgresql, explain, query, performance, database, analysis, optimizer, sql, plan, bottleneck",
"author": "Guja Lomsadze",
"author_email": "Guja Lomsadze <lomsadze.guja@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/5e/46/20ca447a39194473a73e07109c8d8acfdc9695bf0f84f130670628766f57/plananalyze-0.1.0.tar.gz",
"platform": null,
"description": "# `plananalyze`\n\n# PostgreSQL `EXPLAIN` Plan Analyzer - Extract insights from execution plans Query\n\n## For best results, run `EXPLAIN` like so `EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)`\n\n``\n\n# Quickstart\n\n1. Run \"ANALYZE\" on your Query\n2. Copy-paste output from PostgreSQL\n3. Review details :)\n\n```python\nfrom plananalyze import analyze_plan\n\nplan = \"\"\"\nHash Join (cost=12.70..30.50 rows=120 width=743)\n Hash Cond: ((d.name)::text = (employees.department)::text)\n -> Seq Scan on departments d (cost=0.00..14.80 rows=480 width=142)\n -> Hash (cost=11.20..11.20 rows=120 width=601)\n -> Seq Scan on employees (cost=0.00..11.20 rows=120 width=601)\n\"\"\"\n\nresult = analyze_plan(plan, format_type=\"summary\")\nprint(result)\n```\n\nOutput:\n\n```shell\n\ud83d\udcca EXECUTION OVERVIEW:\n Total Cost: 30.50\n Node Count: 5\n\n\ud83d\udd0d OPERATIONS:\n Sequential Scans: 2\n Index Scans: 0\n Joins: 1\n Sorts: 0\n```\n\n# Detailed Response\n\n```python\n# Use format_type=\"detailed\"\nresult = analyze_plan(plan, format_type=\"detailed\")\n```\n\nOutput:\n\n```shell\n\ud83d\udcc8 EXECUTION METRICS:\n Total Cost: 30.50\n Root Operation: Hash Join\n\n\ud83c\udfd7\ufe0f PLAN STRUCTURE:\n Total Nodes: 5\n Plan Depth: 0\n\n\ud83d\udd0d OPERATION BREAKDOWN:\n Sequential Scans: 2\n Index Scans: 0\n Index Only Scans: 0\n Bitmap Scans: 0\n Join Operations: 1\n Sort Operations: 0\n Hash Operations: 2\n Aggregate Operations: 0\n\n\ud83d\udcb0 MOST EXPENSIVE OPERATIONS:\n 1. Hash Join - Cost: 30.50 (100.0%)\n 2. -> Seq Scan on departments - Cost: 14.80 (48.5%)\n 3. -> Hash - Cost: 11.20 (36.7%)\n```\n\n# JSON output\n\n```python\n# Use format_type=\"json\"\nresult = analyze_plan(plan, format_type=\"json\")\n```\n\n# JSON Input\n\n### Run \"explain\" on PostgreSQL query using `EXPLAIN (FORMAT JSON)`\n\n```python\nfrom plananalyze import analyze_plan\n\nplan_json = \"\"\"\n[\n {\n \"Plan\": {\n \"Node Type\": \"Hash Join\",\n \"Parallel Aware\": false,\n \"Async Capable\": false,\n \"Join Type\": \"Inner\",\n \"Startup Cost\": 12.70,\n \"Total Cost\": 30.50,\n \"Plan Rows\": 120,\n \"Plan Width\": 743,\n \"Inner Unique\": false,\n \"Hash Cond\": \"((d.name)::text = (employees.department)::text)\",\n \"Plans\": [\n {\n \"Node Type\": \"Seq Scan\",\n \"Parent Relationship\": \"Outer\",\n \"Parallel Aware\": false,\n \"Async Capable\": false,\n \"Relation Name\": \"departments\",\n \"Alias\": \"d\",\n \"Startup Cost\": 0.00,\n \"Total Cost\": 14.80,\n \"Plan Rows\": 480,\n \"Plan Width\": 142\n },\n {\n \"Node Type\": \"Hash\",\n \"Parent Relationship\": \"Inner\",\n \"Parallel Aware\": false,\n \"Async Capable\": false,\n \"Startup Cost\": 11.20,\n \"Total Cost\": 11.20,\n \"Plan Rows\": 120,\n \"Plan Width\": 601,\n \"Plans\": [\n {\n \"Node Type\": \"Seq Scan\",\n \"Parent Relationship\": \"Outer\",\n \"Parallel Aware\": false,\n \"Async Capable\": false,\n \"Relation Name\": \"employees\",\n \"Alias\": \"employees\",\n \"Startup Cost\": 0.00,\n \"Total Cost\": 11.20,\n \"Plan Rows\": 120,\n \"Plan Width\": 601\n }\n ]\n }\n ]\n }\n }\n]\n\"\"\"\n\nresult = analyze_plan(plan_json, format_type=\"summary\")\nprint(result)\n```\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "PostgreSQL EXPLAIN Plan Analyzer - Extract insights from execution plans",
"version": "0.1.0",
"project_urls": {
"Bug Tracker": "https://github.com/GujaLomsadze/PlanAnalyzer/issues",
"Homepage": "https://github.com/GujaLomsadze/PlanAnalyzer",
"Repository": "https://github.com/GujaLomsadze/PlanAnalyzer.git"
},
"split_keywords": [
"postgresql",
" explain",
" query",
" performance",
" database",
" analysis",
" optimizer",
" sql",
" plan",
" bottleneck"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "7fc3bf1c6bde8e2d20a594e6512b3b823b6d58cfdb79ce42b4a8240fdd69a3fb",
"md5": "b6ad6b5cd293276915f5eab5e728386d",
"sha256": "94ebb9be8599c163f50e8e21f91bfe1503d9e35ce46d1705110a3ab9d6f470be"
},
"downloads": -1,
"filename": "plananalyze-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "b6ad6b5cd293276915f5eab5e728386d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 30172,
"upload_time": "2025-09-14T15:39:39",
"upload_time_iso_8601": "2025-09-14T15:39:39.048931Z",
"url": "https://files.pythonhosted.org/packages/7f/c3/bf1c6bde8e2d20a594e6512b3b823b6d58cfdb79ce42b4a8240fdd69a3fb/plananalyze-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "5e4620ca447a39194473a73e07109c8d8acfdc9695bf0f84f130670628766f57",
"md5": "8aae27875652f9121f0c1c1b26b31310",
"sha256": "30ff96a8e32ee235fb67b472e52d0da330eba7563a3928bc3ae9bc35aecfcb1a"
},
"downloads": -1,
"filename": "plananalyze-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "8aae27875652f9121f0c1c1b26b31310",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 29475,
"upload_time": "2025-09-14T15:39:41",
"upload_time_iso_8601": "2025-09-14T15:39:41.140752Z",
"url": "https://files.pythonhosted.org/packages/5e/46/20ca447a39194473a73e07109c8d8acfdc9695bf0f84f130670628766f57/plananalyze-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-14 15:39:41",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "GujaLomsadze",
"github_project": "PlanAnalyzer",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "PyYAML",
"specs": [
[
">=",
"6.0"
]
]
},
{
"name": "lxml",
"specs": [
[
">=",
"4.9.0"
]
]
}
],
"tox": true,
"lcname": "plananalyze"
}