@evertonferreira96/agents 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/api.md +45 -0
- package/.claude/agents/app.md +41 -0
- package/.claude/agents/architect.md +49 -0
- package/.claude/agents/infra.md +27 -0
- package/.claude/agents/product.md +58 -0
- package/.claude/agents/quick.md +33 -0
- package/.claude/agents/security.md +39 -0
- package/.claude/agents/ui.md +54 -0
- package/.claude/agents/verifier.md +56 -0
- package/.claude/agents/web.md +41 -0
- package/.claude/hooks/config-update-check.mjs +14 -0
- package/.claude/hooks/context-budget.mjs +51 -0
- package/.claude/hooks/graphify-update.sh +16 -0
- package/.claude/hooks/guard-bash.sh +64 -0
- package/.claude/hooks/orchestrator-guard.sh +49 -0
- package/.claude/hooks/post-compact.sh +26 -0
- package/.claude/hooks/readonly-guard.sh +54 -0
- package/.claude/hooks/stop-verify.sh +52 -0
- package/.claude/rules/api.md +21 -0
- package/.claude/rules/db.md +9 -0
- package/.claude/rules/delivery-diagram.md +16 -0
- package/.claude/rules/git-workflow.md +34 -0
- package/.claude/rules/graphify.md +3 -0
- package/.claude/rules/mobile.md +22 -0
- package/.claude/rules/tickets.md +9 -0
- package/.claude/rules/ui.md +14 -0
- package/.claude/rules/web.md +27 -0
- package/.claude/settings.json +114 -0
- package/.claude/skills/animate/RECIPES.md +324 -0
- package/.claude/skills/animate/SKILL.md +208 -0
- package/.claude/skills/animate/agents/openai.yaml +5 -0
- package/.claude/skills/animate-expo/RECIPES.md +385 -0
- package/.claude/skills/animate-expo/SKILL.md +264 -0
- package/.claude/skills/animate-expo/agents/openai.yaml +5 -0
- package/.claude/skills/animation-performance/SKILL.md +223 -0
- package/.claude/skills/animation-performance/agents/openai.yaml +5 -0
- package/.claude/skills/apple-design/SKILL.md +291 -0
- package/.claude/skills/apple-design/agents/openai.yaml +5 -0
- package/.claude/skills/arch-api/SKILL.md +291 -0
- package/.claude/skills/arch-api/agents/openai.yaml +3 -0
- package/.claude/skills/arch-api/references/common.md +174 -0
- package/.claude/skills/arch-api/references/contract.md +289 -0
- package/.claude/skills/arch-api/references/domain.md +301 -0
- package/.claude/skills/arch-api/references/endpoints.md +184 -0
- package/.claude/skills/arch-api/references/review.md +228 -0
- package/.claude/skills/arch-api/references/security.md +151 -0
- package/.claude/skills/arch-app/SKILL.md +278 -0
- package/.claude/skills/arch-app/agents/openai.yaml +3 -0
- package/.claude/skills/arch-app/references/navigation-session.md +257 -0
- package/.claude/skills/arch-app/references/review.md +155 -0
- package/.claude/skills/arch-app/references/screens.md +214 -0
- package/.claude/skills/arch-app/references/services.md +301 -0
- package/.claude/skills/arch-app/references/ui-mobile.md +124 -0
- package/.claude/skills/arch-db/SKILL.md +181 -0
- package/.claude/skills/arch-db/agents/openai.yaml +3 -0
- package/.claude/skills/arch-db/references/indexes-queries.md +251 -0
- package/.claude/skills/arch-db/references/migrations.md +191 -0
- package/.claude/skills/arch-db/references/modeling.md +214 -0
- package/.claude/skills/arch-db/references/mysql.md +262 -0
- package/.claude/skills/arch-db/references/pooling-ops.md +112 -0
- package/.claude/skills/arch-db/references/review.md +143 -0
- package/.claude/skills/arch-db/references/transactions-locks.md +141 -0
- package/.claude/skills/arch-web/SKILL.md +307 -0
- package/.claude/skills/arch-web/agents/openai.yaml +3 -0
- package/.claude/skills/arch-web/references/auth-session-env.md +165 -0
- package/.claude/skills/arch-web/references/blocks.md +198 -0
- package/.claude/skills/arch-web/references/cache.md +124 -0
- package/.claude/skills/arch-web/references/review.md +142 -0
- package/.claude/skills/arch-web/references/services.md +297 -0
- package/.claude/skills/arch-web/references/tests.md +159 -0
- package/.claude/skills/arch-web/references/ui-forms.md +143 -0
- package/.claude/skills/break-ui/CATALOG.md +135 -0
- package/.claude/skills/break-ui/SKILL.md +176 -0
- package/.claude/skills/break-ui/agents/openai.yaml +5 -0
- package/.claude/skills/brief/SKILL.md +91 -0
- package/.claude/skills/brief/agents/openai.yaml +3 -0
- package/.claude/skills/diagnosing-bugs/SKILL.md +138 -0
- package/.claude/skills/diagnosing-bugs/agents/openai.yaml +3 -0
- package/.claude/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
- package/.claude/skills/emil-design-eng/SKILL.md +675 -0
- package/.claude/skills/emil-design-eng/agents/openai.yaml +5 -0
- package/.claude/skills/find-animation-opportunities/SKILL.md +141 -0
- package/.claude/skills/find-animation-opportunities/agents/openai.yaml +5 -0
- package/.claude/skills/graphify/.graphify_version +1 -0
- package/.claude/skills/graphify/SKILL.md +742 -0
- package/.claude/skills/graphify/agents/openai.yaml +3 -0
- package/.claude/skills/graphify/references/add-watch.md +56 -0
- package/.claude/skills/graphify/references/exports.md +91 -0
- package/.claude/skills/graphify/references/extraction-spec.md +70 -0
- package/.claude/skills/graphify/references/github-and-merge.md +46 -0
- package/.claude/skills/graphify/references/hooks.md +33 -0
- package/.claude/skills/graphify/references/query.md +317 -0
- package/.claude/skills/graphify/references/transcribe.md +52 -0
- package/.claude/skills/graphify/references/update.md +221 -0
- package/.claude/skills/grill-me/SKILL.md +7 -0
- package/.claude/skills/grill-me/agents/openai.yaml +5 -0
- package/.claude/skills/grill-with-docs/SKILL.md +64 -0
- package/.claude/skills/grill-with-docs/agents/openai.yaml +5 -0
- package/.claude/skills/grilling/SKILL.md +30 -0
- package/.claude/skills/grilling/agents/openai.yaml +3 -0
- package/.claude/skills/handoff/SKILL.md +28 -0
- package/.claude/skills/handoff/agents/openai.yaml +5 -0
- package/.claude/skills/impeccable/SKILL.md +89 -0
- package/.claude/skills/impeccable/agents/openai.yaml +5 -0
- package/.claude/skills/impeccable/reference/adapt.md +318 -0
- package/.claude/skills/impeccable/reference/adapt.native.md +58 -0
- package/.claude/skills/impeccable/reference/android.md +46 -0
- package/.claude/skills/impeccable/reference/animate.md +89 -0
- package/.claude/skills/impeccable/reference/audit.md +137 -0
- package/.claude/skills/impeccable/reference/audit.native.md +139 -0
- package/.claude/skills/impeccable/reference/bolder.md +33 -0
- package/.claude/skills/impeccable/reference/clarify.md +94 -0
- package/.claude/skills/impeccable/reference/colorize.md +86 -0
- package/.claude/skills/impeccable/reference/component-review.md +63 -0
- package/.claude/skills/impeccable/reference/craft-floor.md +44 -0
- package/.claude/skills/impeccable/reference/craft.md +5 -0
- package/.claude/skills/impeccable/reference/critique.md +809 -0
- package/.claude/skills/impeccable/reference/degraded/asset-producer.md +42 -0
- package/.claude/skills/impeccable/reference/degraded/documenter.md +24 -0
- package/.claude/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
- package/.claude/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
- package/.claude/skills/impeccable/reference/delight.md +70 -0
- package/.claude/skills/impeccable/reference/distill.md +111 -0
- package/.claude/skills/impeccable/reference/doctor.md +54 -0
- package/.claude/skills/impeccable/reference/document.md +416 -0
- package/.claude/skills/impeccable/reference/extract.md +69 -0
- package/.claude/skills/impeccable/reference/generate.md +101 -0
- package/.claude/skills/impeccable/reference/harden.md +345 -0
- package/.claude/skills/impeccable/reference/hooks.md +113 -0
- package/.claude/skills/impeccable/reference/init.md +131 -0
- package/.claude/skills/impeccable/reference/ios.md +51 -0
- package/.claude/skills/impeccable/reference/layout.md +84 -0
- package/.claude/skills/impeccable/reference/live-setup.md +104 -0
- package/.claude/skills/impeccable/reference/live.md +325 -0
- package/.claude/skills/impeccable/reference/mode-operate.md +21 -0
- package/.claude/skills/impeccable/reference/mode-persuade.md +19 -0
- package/.claude/skills/impeccable/reference/mode-read.md +21 -0
- package/.claude/skills/impeccable/reference/new-work.md +154 -0
- package/.claude/skills/impeccable/reference/onboard.md +234 -0
- package/.claude/skills/impeccable/reference/operate.md +61 -0
- package/.claude/skills/impeccable/reference/optimize.md +258 -0
- package/.claude/skills/impeccable/reference/overdrive.md +127 -0
- package/.claude/skills/impeccable/reference/polish.md +105 -0
- package/.claude/skills/impeccable/reference/quieter.md +99 -0
- package/.claude/skills/impeccable/reference/region-map.md +26 -0
- package/.claude/skills/impeccable/reference/routing.md +24 -0
- package/.claude/skills/impeccable/reference/shape.md +59 -0
- package/.claude/skills/impeccable/reference/typeset.md +80 -0
- package/.claude/skills/impeccable/reference/visualize.md +47 -0
- package/.claude/skills/impeccable/scripts/VERSION +1 -0
- package/.claude/skills/impeccable/scripts/command-metadata.json +98 -0
- package/.claude/skills/impeccable/scripts/data/font-index-failures.json +121 -0
- package/.claude/skills/impeccable/scripts/data/font-index.json +1 -0
- package/.claude/skills/impeccable/scripts/impeccable +206 -0
- package/.claude/skills/impeccable/scripts/impeccable.cmd +214 -0
- package/.claude/skills/impeccable/scripts/live-browser-dom.js +281 -0
- package/.claude/skills/impeccable/scripts/live-browser-ignores.js +242 -0
- package/.claude/skills/impeccable/scripts/live-browser-session.js +148 -0
- package/.claude/skills/impeccable/scripts/live-browser.js +13532 -0
- package/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/.claude/skills/improve-animations/AUDIT.md +115 -0
- package/.claude/skills/improve-animations/PLAN-TEMPLATE.md +73 -0
- package/.claude/skills/improve-animations/SKILL.md +110 -0
- package/.claude/skills/improve-animations/agents/openai.yaml +5 -0
- package/.claude/skills/mobile-native/SKILL.md +311 -0
- package/.claude/skills/mobile-native/agents/openai.yaml +3 -0
- package/.claude/skills/orchestrate/SKILL.md +181 -0
- package/.claude/skills/orchestrate/agents/openai.yaml +3 -0
- package/.claude/skills/pick-ui-library/SKILL.md +85 -0
- package/.claude/skills/pick-ui-library/agents/openai.yaml +5 -0
- package/.claude/skills/ponytail/SKILL.md +52 -0
- package/.claude/skills/ponytail/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-audit/SKILL.md +103 -0
- package/.claude/skills/ponytail-audit/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-debt/SKILL.md +44 -0
- package/.claude/skills/ponytail-debt/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-review/SKILL.md +101 -0
- package/.claude/skills/ponytail-review/agents/openai.yaml +3 -0
- package/.claude/skills/postgres-best-practices/SKILL.md +42 -0
- package/.claude/skills/postgres-best-practices/agents/openai.yaml +3 -0
- package/.claude/skills/postgres-best-practices/references/backup-restore.md +372 -0
- package/.claude/skills/postgres-best-practices/references/bulk-loading.md +315 -0
- package/.claude/skills/postgres-best-practices/references/connection-pooling.md +310 -0
- package/.claude/skills/postgres-best-practices/references/hot-standby.md +221 -0
- package/.claude/skills/postgres-best-practices/references/indexing.md +318 -0
- package/.claude/skills/postgres-best-practices/references/logical-replication.md +610 -0
- package/.claude/skills/postgres-best-practices/references/major-version-upgrades.md +334 -0
- package/.claude/skills/postgres-best-practices/references/performance-diagnostics.md +553 -0
- package/.claude/skills/postgres-best-practices/references/query-optimization.md +294 -0
- package/.claude/skills/postgres-best-practices/references/query-patterns.md +566 -0
- package/.claude/skills/postgres-best-practices/references/schema-design.md +362 -0
- package/.claude/skills/postgres-best-practices/references/security-roles.md +489 -0
- package/.claude/skills/postgres-best-practices/references/transaction-isolation.md +344 -0
- package/.claude/skills/project-docs/SKILL.md +330 -0
- package/.claude/skills/project-docs/agents/openai.yaml +3 -0
- package/.claude/skills/prototype/PICKER.md +197 -0
- package/.claude/skills/prototype/SKILL.md +98 -0
- package/.claude/skills/prototype/agents/openai.yaml +5 -0
- package/.claude/skills/retro/SKILL.md +43 -0
- package/.claude/skills/retro/agents/openai.yaml +5 -0
- package/.claude/skills/review/SKILL.md +74 -0
- package/.claude/skills/review/agents/openai.yaml +3 -0
- package/.claude/skills/review/references/smells.md +23 -0
- package/.claude/skills/review-animations/SKILL.md +120 -0
- package/.claude/skills/review-animations/STANDARDS.md +187 -0
- package/.claude/skills/review-animations/agents/openai.yaml +5 -0
- package/.claude/skills/tdd/SKILL.md +38 -0
- package/.claude/skills/tdd/agents/openai.yaml +3 -0
- package/.claude/skills/tdd/mocking.md +59 -0
- package/.claude/skills/tdd/tests.md +77 -0
- package/.claude/skills/triage/SKILL.md +58 -0
- package/.claude/skills/triage/agents/openai.yaml +3 -0
- package/.claude/skills/ui-ux-pro-max/SKILL.md +378 -0
- package/.claude/skills/ui-ux-pro-max/agents/openai.yaml +5 -0
- package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.claude/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/.claude/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
- package/.claude/skills/writing-for-agents/SKILL.md +81 -0
- package/.claude/skills/writing-for-agents/agents/openai.yaml +3 -0
- package/.worktreeinclude +3 -0
- package/AGENTS.md +44 -0
- package/README.md +14 -2
- package/VERSION +1 -0
- package/bin/agents.mjs +45 -0
- package/docs/adr/README.md +31 -0
- package/docs/brief-template.md +3 -0
- package/docs/plans/README.md +73 -0
- package/package.json +46 -4
- package/scripts/bootstrap.mjs +188 -0
- package/scripts/check-catalog.mjs +43 -0
- package/scripts/skills-update.mjs +51 -0
- package/skills-lock.json +269 -0
- package/templates/CLAUDE.project.md +41 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Query Optimization Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- Running EXPLAIN ANALYZE
|
|
5
|
+
- Reading execution plans
|
|
6
|
+
- Plan node reference
|
|
7
|
+
- Join strategy selection
|
|
8
|
+
- Common bottlenecks and fixes
|
|
9
|
+
- Statistics and the planner
|
|
10
|
+
- Configuration tuning knobs
|
|
11
|
+
|
|
12
|
+
## Running EXPLAIN ANALYZE
|
|
13
|
+
|
|
14
|
+
Always use this form for real diagnostics:
|
|
15
|
+
|
|
16
|
+
```sql
|
|
17
|
+
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) SELECT ...;
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| Flag | Purpose |
|
|
21
|
+
|------|---------|
|
|
22
|
+
| `ANALYZE` | Actually executes the query (required for actual times/rows) |
|
|
23
|
+
| `BUFFERS` | Shows shared/local buffer hits and reads (I/O insight). **PG18+**: included by default with `ANALYZE` |
|
|
24
|
+
| `FORMAT TEXT` | Human-readable output (default) |
|
|
25
|
+
|
|
26
|
+
Additional EXPLAIN options:
|
|
27
|
+
|
|
28
|
+
| Flag | PG Version | Purpose |
|
|
29
|
+
|------|-----------|---------|
|
|
30
|
+
| `GENERIC_PLAN` | PG16+ | Show plan for parameterized queries (with `$1` params) without executing |
|
|
31
|
+
| `MEMORY` | PG17+ | Report planner memory usage |
|
|
32
|
+
| `SERIALIZE` | PG17+ | Show cost of converting result data for network transmission |
|
|
33
|
+
|
|
34
|
+
**PG18 EXPLAIN improvements:**
|
|
35
|
+
- `BUFFERS` is now included automatically with `ANALYZE` — no need to specify it separately
|
|
36
|
+
- Index scan nodes report the number of index lookups
|
|
37
|
+
- Memory/disk usage shown for Materialize, Window Aggregate, and CTE Scan nodes
|
|
38
|
+
- Fractional row counts in output (instead of rounding to integers)
|
|
39
|
+
- Disabled nodes are explicitly indicated in output
|
|
40
|
+
|
|
41
|
+
For queries that modify data, wrap in a transaction and rollback:
|
|
42
|
+
|
|
43
|
+
```sql
|
|
44
|
+
BEGIN;
|
|
45
|
+
EXPLAIN (ANALYZE, BUFFERS) DELETE FROM orders WHERE ...;
|
|
46
|
+
ROLLBACK;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Key Metrics in Output
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
Seq Scan on orders (cost=0.00..1520.00 rows=50000 width=64)
|
|
53
|
+
(actual time=0.012..15.432 rows=48573 loops=1)
|
|
54
|
+
Buffers: shared hit=520 read=200
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- **cost**: Estimated startup..total cost (arbitrary planner units)
|
|
58
|
+
- **rows**: Estimated row count
|
|
59
|
+
- **actual time**: Real time in ms (startup..total)
|
|
60
|
+
- **actual rows**: Real row count — compare to estimate
|
|
61
|
+
- **loops**: How many times this node executed
|
|
62
|
+
- **Buffers shared hit**: Pages found in cache
|
|
63
|
+
- **Buffers shared read**: Pages read from disk
|
|
64
|
+
|
|
65
|
+
**Critical check**: If estimated `rows` and actual `rows` differ by 10x+, statistics are stale or the planner is misestimating.
|
|
66
|
+
|
|
67
|
+
## Reading Execution Plans
|
|
68
|
+
|
|
69
|
+
Read bottom-up, innermost to outermost. Each node:
|
|
70
|
+
1. Scans or receives input rows
|
|
71
|
+
2. Applies filtering or transformation
|
|
72
|
+
3. Passes rows to the parent node
|
|
73
|
+
|
|
74
|
+
### Identifying the Bottleneck
|
|
75
|
+
|
|
76
|
+
1. Find the node with the highest `actual time` (total, not startup)
|
|
77
|
+
2. Check if actual rows >> estimated rows (bad statistics)
|
|
78
|
+
3. Check `Buffers: shared read` — high reads = cold cache or missing index
|
|
79
|
+
4. Look for `Rows Removed by Filter` — high values mean the scan is too broad
|
|
80
|
+
|
|
81
|
+
## Plan Node Reference
|
|
82
|
+
|
|
83
|
+
### Scan Nodes
|
|
84
|
+
|
|
85
|
+
| Node | Meaning | When it's a problem |
|
|
86
|
+
|------|---------|-------------------|
|
|
87
|
+
| `Seq Scan` | Full table scan | On large tables when only a few rows match |
|
|
88
|
+
| `Index Scan` | B-tree lookup + heap fetch | Normal and expected |
|
|
89
|
+
| `Index Only Scan` | B-tree lookup, no heap fetch | Best case — all columns in index |
|
|
90
|
+
| `Bitmap Index Scan` + `Bitmap Heap Scan` | Index lookup → bitmap → heap | Good for medium selectivity |
|
|
91
|
+
| `CTE Scan` | Reads from materialized CTE | Check if CTE materialization is needed |
|
|
92
|
+
|
|
93
|
+
**When is Seq Scan OK?**
|
|
94
|
+
- Table is small (< few thousand rows)
|
|
95
|
+
- Query returns > 10-20% of rows
|
|
96
|
+
- No usable index exists and adding one isn't warranted
|
|
97
|
+
|
|
98
|
+
### Join Nodes
|
|
99
|
+
|
|
100
|
+
| Node | How it works | Best for |
|
|
101
|
+
|------|-------------|----------|
|
|
102
|
+
| `Nested Loop` | For each outer row, scan inner | Small outer set + indexed inner |
|
|
103
|
+
| `Hash Join` | Build hash table on inner, probe with outer | Medium-large equijoins, enough work_mem |
|
|
104
|
+
| `Merge Join` | Both inputs sorted, merge | Pre-sorted inputs or sorted output needed |
|
|
105
|
+
|
|
106
|
+
**Nested Loop red flags**: high outer row count with no index on the inner side.
|
|
107
|
+
|
|
108
|
+
**Hash Join red flags**: `Batches: N` where N > 1 means hash table spilled to disk (increase `work_mem`).
|
|
109
|
+
|
|
110
|
+
### Sort and Aggregate Nodes
|
|
111
|
+
|
|
112
|
+
| Node | Notes |
|
|
113
|
+
|------|-------|
|
|
114
|
+
| `Sort` | Check `Sort Method: external merge` = disk spill (increase `work_mem`) |
|
|
115
|
+
| `HashAggregate` | Groups via hash table — check for disk spill batches |
|
|
116
|
+
| `GroupAggregate` | Groups pre-sorted input — needs sorted input |
|
|
117
|
+
| `Incremental Sort` | Sorts remaining columns when leading columns already sorted |
|
|
118
|
+
|
|
119
|
+
### Other Nodes
|
|
120
|
+
|
|
121
|
+
| Node | Notes |
|
|
122
|
+
|------|-------|
|
|
123
|
+
| `Materialize` | Caches a subplan's output for re-scan |
|
|
124
|
+
| `Memoize` (PG14+) | Caches parameterized nested loop inner-side results. Look for `Hits: N Misses: N` — high hit ratio means effective caching. Poor cache ratio may indicate high cardinality on the join key |
|
|
125
|
+
| `Gather` / `Gather Merge` | Collects results from parallel workers |
|
|
126
|
+
| `Append` | Concatenates results (UNION ALL, partitioned tables) |
|
|
127
|
+
| `SubPlan` | Correlated subquery — potentially executed per row |
|
|
128
|
+
|
|
129
|
+
## Common Bottlenecks and Fixes
|
|
130
|
+
|
|
131
|
+
### Sequential Scan on Large Table
|
|
132
|
+
|
|
133
|
+
**Symptom**: `Seq Scan` with `Rows Removed by Filter: 999000` (scanned 1M, kept 1K)
|
|
134
|
+
|
|
135
|
+
**Fixes**:
|
|
136
|
+
1. Add an index on the WHERE clause columns
|
|
137
|
+
2. If query returns > 20% of rows, seq scan may actually be optimal
|
|
138
|
+
3. Check `enable_seqscan = on` isn't masking the real issue
|
|
139
|
+
|
|
140
|
+
### Nested Loop with High Row Count
|
|
141
|
+
|
|
142
|
+
**Symptom**: `Nested Loop (actual loops=50000)` with inner `Seq Scan`
|
|
143
|
+
|
|
144
|
+
**Fixes**:
|
|
145
|
+
1. Add index on the inner table's join column
|
|
146
|
+
2. If both sides are large, the planner should choose hash/merge join — check statistics
|
|
147
|
+
|
|
148
|
+
### Sort Spilling to Disk
|
|
149
|
+
|
|
150
|
+
**Symptom**: `Sort Method: external merge Disk: 125MB`
|
|
151
|
+
|
|
152
|
+
**Fixes**:
|
|
153
|
+
1. Increase `work_mem` (per-operation, not global): `SET work_mem = '256MB';`
|
|
154
|
+
2. Add an index matching the ORDER BY to avoid sorting entirely
|
|
155
|
+
3. If in a CTE or subquery, consider whether the sort is necessary
|
|
156
|
+
|
|
157
|
+
### Bad Row Estimates
|
|
158
|
+
|
|
159
|
+
**Symptom**: Estimated rows: 1, Actual rows: 500,000
|
|
160
|
+
|
|
161
|
+
**Fixes**:
|
|
162
|
+
1. `ANALYZE table_name;` — refresh statistics
|
|
163
|
+
2. Increase `default_statistics_target` for columns with skewed distributions:
|
|
164
|
+
```sql
|
|
165
|
+
ALTER TABLE orders ALTER COLUMN status SET STATISTICS 1000;
|
|
166
|
+
ANALYZE orders;
|
|
167
|
+
```
|
|
168
|
+
3. Create extended statistics for correlated columns:
|
|
169
|
+
```sql
|
|
170
|
+
CREATE STATISTICS orders_status_date (dependencies)
|
|
171
|
+
ON status, created_at FROM orders;
|
|
172
|
+
ANALYZE orders;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Correlated SubPlan Executed Per Row
|
|
176
|
+
|
|
177
|
+
**Symptom**: `SubPlan` node with `loops=100000`
|
|
178
|
+
|
|
179
|
+
**Fix**: Rewrite as a JOIN or lateral join:
|
|
180
|
+
|
|
181
|
+
```sql
|
|
182
|
+
-- Bad: correlated subquery
|
|
183
|
+
SELECT *, (SELECT name FROM departments d WHERE d.id = e.dept_id) AS dept_name
|
|
184
|
+
FROM employees e;
|
|
185
|
+
|
|
186
|
+
-- Good: join
|
|
187
|
+
SELECT e.*, d.name AS dept_name
|
|
188
|
+
FROM employees e
|
|
189
|
+
JOIN departments d ON d.id = e.dept_id;
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### PG18 Optimizer Improvements
|
|
193
|
+
|
|
194
|
+
**B-tree skip scan (PG18+)**: Multi-column B-tree indexes can now be used even when there are no restrictions on the leading columns. Previously a composite index on `(tenant_id, created_at)` was useless for `WHERE created_at > '2024-01-01'` without a `tenant_id` filter. PG18 can skip through distinct `tenant_id` values — eliminating many cases where you needed a separate single-column index.
|
|
195
|
+
|
|
196
|
+
**Self-join elimination**: The optimizer automatically removes unnecessary self-joins. Controlled by `enable_self_join_elimination`.
|
|
197
|
+
|
|
198
|
+
**IN to ANY conversion**: `WHERE x IN (VALUES ...)` is converted to `x = ANY(...)` for better use of optimizer statistics.
|
|
199
|
+
|
|
200
|
+
**OR-clause to array transformation**: OR clauses like `WHERE x = 1 OR x = 2 OR x = 3` are transformed to arrays for faster index processing.
|
|
201
|
+
|
|
202
|
+
**DISTINCT reordering**: Keys in `SELECT DISTINCT` can be reordered internally to match an existing index and avoid sorting. Controlled by `enable_distinct_reordering`.
|
|
203
|
+
|
|
204
|
+
**Improved partition planning**: More efficient planning for queries accessing many partitions, with reduced memory usage. Partitionwise joins allowed in more cases.
|
|
205
|
+
|
|
206
|
+
## Statistics and the Planner
|
|
207
|
+
|
|
208
|
+
### Manual ANALYZE
|
|
209
|
+
|
|
210
|
+
```sql
|
|
211
|
+
-- Analyze one table
|
|
212
|
+
ANALYZE orders;
|
|
213
|
+
|
|
214
|
+
-- Analyze specific columns
|
|
215
|
+
ANALYZE orders(status, created_at);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Autovacuum runs ANALYZE automatically, but after bulk loads or major changes, run it manually.
|
|
219
|
+
|
|
220
|
+
### Extended Statistics
|
|
221
|
+
|
|
222
|
+
For correlated columns that the planner estimates independently:
|
|
223
|
+
|
|
224
|
+
```sql
|
|
225
|
+
-- Functional dependency: knowing city tells you the state
|
|
226
|
+
CREATE STATISTICS city_state_dep (dependencies) ON city, state FROM addresses;
|
|
227
|
+
|
|
228
|
+
-- N-distinct: correct group count estimates
|
|
229
|
+
CREATE STATISTICS city_state_ndist (ndistinct) ON city, state FROM addresses;
|
|
230
|
+
|
|
231
|
+
-- MCV lists: track most common value combinations
|
|
232
|
+
CREATE STATISTICS city_state_mcv (mcv) ON city, state FROM addresses;
|
|
233
|
+
|
|
234
|
+
ANALYZE addresses;
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Checking Current Statistics
|
|
238
|
+
|
|
239
|
+
```sql
|
|
240
|
+
SELECT
|
|
241
|
+
attname,
|
|
242
|
+
n_distinct,
|
|
243
|
+
most_common_vals,
|
|
244
|
+
most_common_freqs,
|
|
245
|
+
correlation -- physical vs. logical ordering (affects index scan cost)
|
|
246
|
+
FROM pg_stats
|
|
247
|
+
WHERE tablename = 'orders' AND attname = 'status';
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Configuration Tuning Knobs
|
|
251
|
+
|
|
252
|
+
Except for `shared_buffers`, these parameters can be overridden in the current session with `SET` for workload-specific testing. `shared_buffers` is allocated at server start; persisting a change in `postgresql.conf` or with `ALTER SYSTEM` requires a restart before it takes effect.
|
|
253
|
+
|
|
254
|
+
| Parameter | Default | When to increase |
|
|
255
|
+
|-----------|---------|-----------------|
|
|
256
|
+
| `shared_buffers` | 128MB | Server-wide, restart-required setting; start around 25% of total RAM and validate for the workload. See performance-diagnostics for cache hit rate queries |
|
|
257
|
+
| `work_mem` | 4MB | Sort/hash spilling to disk |
|
|
258
|
+
| `maintenance_work_mem` | 64MB | Slow VACUUM, CREATE INDEX, ALTER TABLE |
|
|
259
|
+
| `effective_cache_size` | 4GB | Set to ~75% of total RAM (hint to planner, no allocation) |
|
|
260
|
+
| `random_page_cost` | 4.0 | SSD storage → set to 1.1-1.5 |
|
|
261
|
+
| `effective_io_concurrency` | 1 (16 in PG18) | SSD storage → set to 200 |
|
|
262
|
+
| `default_statistics_target` | 100 | Bad estimates on skewed columns → 500-1000 |
|
|
263
|
+
| `max_parallel_workers_per_gather` | 2 | Large analytical queries benefit from more parallelism |
|
|
264
|
+
|
|
265
|
+
### SSD-Optimized Settings
|
|
266
|
+
|
|
267
|
+
```sql
|
|
268
|
+
SET random_page_cost = 1.1;
|
|
269
|
+
-- Some platforms without posix_fadvise only support 0.
|
|
270
|
+
DO $$
|
|
271
|
+
BEGIN
|
|
272
|
+
PERFORM set_config('effective_io_concurrency', '200', false);
|
|
273
|
+
EXCEPTION
|
|
274
|
+
WHEN invalid_parameter_value THEN
|
|
275
|
+
PERFORM set_config('effective_io_concurrency', '0', false);
|
|
276
|
+
END
|
|
277
|
+
$$;
|
|
278
|
+
SET effective_cache_size = '24GB'; -- adjust to your server
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
These make the planner more willing to use index scans when measurements show SSD random reads are fast. Some platforms without asynchronous prefetch support cap `effective_io_concurrency` at `0`.
|
|
282
|
+
|
|
283
|
+
### Asynchronous I/O (PG18+)
|
|
284
|
+
|
|
285
|
+
PG18 introduces a native async I/O subsystem that improves sequential scan, bitmap heap scan, and VACUUM performance.
|
|
286
|
+
|
|
287
|
+
| Parameter | Default (PG18) | Purpose |
|
|
288
|
+
|-----------|----------------|---------|
|
|
289
|
+
| `io_method` | platform-dependent | I/O method: `sync`, `io_uring` (Linux), `posix_aio` |
|
|
290
|
+
| `io_combine_limit` | 128kB | Max size of combined I/O operations |
|
|
291
|
+
| `effective_io_concurrency` | 16 (was 1) | Default raised significantly in PG18 |
|
|
292
|
+
| `maintenance_io_concurrency` | 16 (was 10) | Default raised for maintenance operations |
|
|
293
|
+
|
|
294
|
+
The raised defaults mean PG18 out-of-the-box performance for sequential scans and VACUUM is significantly better than prior versions.
|