원클릭으로
db-analyze-hotpaths
Run EXPLAIN ANALYZE on common/critical queries to identify performance issues
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Run EXPLAIN ANALYZE on common/critical queries to identify performance issues
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Execute story development with selectable automation modes to accommodate different developer preferences, skill levels, and story complexity.
Set up a Kord-aligned documentation baseline (no legacy frameworks)
Create Next Story Task methodology and workflow
Validate Next Story Task methodology and workflow
advanced-elicitation methodology and workflow
No checklists needed - this task facilitates brainstorming sessions, validation is through user interaction methodology and workflow
| name | db-analyze-hotpaths |
| description | Run EXPLAIN ANALYZE on common/critical queries to identify performance issues |
| agent | architect |
| subtask | false |
Run EXPLAIN ANALYZE on common/critical queries to identify performance issues
Parameter:* mode (optional, default: interactive)
Purpose:* Definitive pass/fail criteria for task completion
Checklist:*
acceptance-criteria:
- [ ] Data persisted correctly; constraints respected; no orphaned data
type: acceptance-criterion
blocker: true
validation: |
Assert data persisted correctly; constraints respected; no orphaned data
error_message: "Acceptance criterion not met: Data persisted correctly; constraints respected; no orphaned data"
Strategy:* fallback
Common Errors:*
Error:* Connection Failed
Error:* Query Syntax Error
Error:* Transaction Rollback
queries_file (optional): Path to file with labeled queries to analyzeEnsure performance monitoring is available:
echo "Enabling performance extensions..."
psql "$SUPABASE_DB_URL" << 'EOF'
-- Enable pg_stat_statements (should already be enabled in Supabase)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Optionally enable index_advisor (Supabase extension)
CREATE EXTENSION IF NOT EXISTS index_advisor;
SELECT 'Extensions ready' AS status;
EOF
echo "✓ Extensions enabled"
If no queries_file provided, find slowest queries from pg_stat_statements:
echo "Finding slow queries from pg_stat_statements..."
psql "$SUPABASE_DB_URL" << 'EOF'
SELECT
query,
calls,
ROUND(total_exec_time::numeric, 2) AS total_time_ms,
ROUND(mean_exec_time::numeric, 2) AS mean_time_ms,
ROUND(max_exec_time::numeric, 2) AS max_time_ms,
ROUND((100 * total_exec_time / SUM(total_exec_time) OVER ())::numeric, 2) AS pct_total_time
FROM pg_stat_statements
WHERE query NOT LIKE '%pg_stat_statements%'
AND query NOT LIKE '%pg_catalog%'
ORDER BY mean_exec_time DESC
LIMIT 20;
EOF
Ask user:
Top 20 slow queries found.
Select query numbers to analyze (comma-separated, e.g., 1,3,5):
Or type 'all' to analyze all:
For each selected query, run comprehensive analysis:
echo "Analyzing query performance..."
# CRITICAL: Always use ANALYZE, BUFFERS for complete picture
psql "$SUPABASE_DB_URL" << 'EOF'
-- Query being analyzed
\echo '=========================================='
\echo 'QUERY: {query_label}'
\echo '=========================================='
-- Option 1: EXPLAIN ANALYZE with BUFFERS (recommended)
EXPLAIN (
ANALYZE true,
BUFFERS true,
VERBOSE true,
COSTS true,
TIMING true
)
{actual_query};
\echo ''
\echo 'BUFFERS LEGEND:'
\echo ' - shared hit = blocks found in buffer cache (good)'
\echo ' - shared read = blocks read from disk (bad if high)'
\echo ' - temp read/written = temporary files (bad if present)'
\echo ''
EOF
Use index_advisor extension (Supabase-specific):
echo "Generating index recommendations..."
psql "$SUPABASE_DB_URL" << 'EOF'
-- Use index_advisor to get suggestions
SELECT *
FROM index_advisor('{actual_query}');
-- Alternative: Supabase Studio has Index Advisor UI
-- Navigate to: Query Performance Report → Select query → "indexes" tab
EOF
Identify common performance issues:
echo "Performance Issue Checklist:"
echo ""
echo "🔍 Sequential Scans:"
echo " - Look for: 'Seq Scan on table_name'"
echo " - Problem if: Large tables (>1000 rows) + filter removes many rows"
echo " - Fix: Add index on filter columns"
echo ""
echo "🔍 Row Count Mismatches:"
echo " - Compare: rows=XXXX (estimated) vs actual rows=YYYY"
echo " - Problem if: Estimate differs by >10x from actual"
echo " - Fix: ANALYZE table_name; (update statistics)"
echo ""
echo "🔍 Buffer Cache Misses:"
echo " - Look for: 'shared read' in BUFFERS output"
echo " - Problem if: High compared to 'shared hit'"
echo " - Fix: Increase shared_buffers, optimize query, add indexes"
echo ""
echo "🔍 Temporary Files:"
echo " - Look for: 'temp read' or 'temp written' in BUFFERS"
echo " - Problem: Query using disk for sorting/hashing (work_mem too small)"
echo " - Fix: Increase work_mem, optimize query, add indexes"
echo ""
echo "🔍 Nested Loops:"
echo " - Look for: 'Nested Loop' with high row counts"
echo " - Problem if: Loops=10000+ iterations"
echo " - Fix: Add indexes on join columns, consider Hash Join"
echo ""
Generate markdown report with findings:
REPORT_FILE="supabase/docs/performance-analysis-$(date +%Y%m%d%H%M%S).md"
mkdir -p supabase/docs
cat > "$REPORT_FILE" << 'MDEOF'
# Query Performance Analysis
*Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
*Database**: [redacted]
*Tool**: DB Sage db-analyze-hotpaths
---
## Executive Summary
- Queries analyzed: {count}
- Avg execution time: {avg_time}ms
- Indexes recommended: {index_count}
---
### Query 1: {query_label}
*Current Performance:**
- Mean execution time: {mean_time}ms
- Calls: {calls}
- % of total time: {pct_time}%
*EXPLAIN ANALYZE Output:**
{explain_output}
*Issues Identified:**
1. {issue_1}
2. {issue_2}
*Recommended Indexes:**
```sql
{recommended_indexes}
Expected Improvement:* {estimated_improvement}
[Repeat for each query...]
MDEOF
echo "✓ Report: $REPORT_FILE"
---
## Output
Display summary and next steps:
✅ HOT PATH ANALYSIS COMPLETE
Queries analyzed: {count} Report: supabase/docs/performance-analysis-{timestamp}.md
Key Findings:
Recommended Actions:
Index Recommendations: {list of CREATE INDEX statements}
---
### Pattern 1: User-Specific Data
```sql
-- Hot path: Get user's posts
SELECT * FROM posts WHERE user_id = 'xxx';
-- Check: Index on user_id exists?
-- Verify: USING (auth.uid() = user_id) is wrapped in SELECT for RLS performance
-- Hot path: Posts with author info
SELECT p.*, u.name
FROM posts p
JOIN users u ON p.user_id = u.id;
-- Check: Index on posts(user_id)? Index on users(id) should exist (PK)
-- Hot path: Recent published posts
SELECT * FROM posts
WHERE status = 'published'
ORDER BY created_at DESC
LIMIT 10;
-- Check: Index on (status, created_at DESC)?
-- Hot path: User post count
SELECT user_id, COUNT(*)
FROM posts
GROUP BY user_id;
-- Check: Index on user_id? Or denormalize count?
Good (Cached):*
Buffers: shared hit=100
= 100 blocks found in cache (no disk I/O)
Bad (Disk Reads):*
Buffers: shared hit=10 read=990
= Only 10 blocks cached, 990 read from disk
Very Bad (Temp Files):*
Buffers: temp read=5000 written=5000
= Query spilled to disk (work_mem too small)
Target:* Maximize "shared hit", minimize "shared read", zero "temp"
Enable explain in SQL editor first (dev only):
-- Run once in Dashboard SQL Editor
ALTER DATABASE postgres SET app.settings.explain TO 'on';
Then use in code:
const { data, error } = await supabase
.from('posts')
.select('*')
.eq('status', 'published')
.explain({ analyze: true, buffers: true })
EXPLAIN (ANALYZE, BUFFERS)ANALYZE after significant data changes