@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.
Files changed (258) hide show
  1. package/.claude/agents/api.md +45 -0
  2. package/.claude/agents/app.md +41 -0
  3. package/.claude/agents/architect.md +49 -0
  4. package/.claude/agents/infra.md +27 -0
  5. package/.claude/agents/product.md +58 -0
  6. package/.claude/agents/quick.md +33 -0
  7. package/.claude/agents/security.md +39 -0
  8. package/.claude/agents/ui.md +54 -0
  9. package/.claude/agents/verifier.md +56 -0
  10. package/.claude/agents/web.md +41 -0
  11. package/.claude/hooks/config-update-check.mjs +14 -0
  12. package/.claude/hooks/context-budget.mjs +51 -0
  13. package/.claude/hooks/graphify-update.sh +16 -0
  14. package/.claude/hooks/guard-bash.sh +64 -0
  15. package/.claude/hooks/orchestrator-guard.sh +49 -0
  16. package/.claude/hooks/post-compact.sh +26 -0
  17. package/.claude/hooks/readonly-guard.sh +54 -0
  18. package/.claude/hooks/stop-verify.sh +52 -0
  19. package/.claude/rules/api.md +21 -0
  20. package/.claude/rules/db.md +9 -0
  21. package/.claude/rules/delivery-diagram.md +16 -0
  22. package/.claude/rules/git-workflow.md +34 -0
  23. package/.claude/rules/graphify.md +3 -0
  24. package/.claude/rules/mobile.md +22 -0
  25. package/.claude/rules/tickets.md +9 -0
  26. package/.claude/rules/ui.md +14 -0
  27. package/.claude/rules/web.md +27 -0
  28. package/.claude/settings.json +114 -0
  29. package/.claude/skills/animate/RECIPES.md +324 -0
  30. package/.claude/skills/animate/SKILL.md +208 -0
  31. package/.claude/skills/animate/agents/openai.yaml +5 -0
  32. package/.claude/skills/animate-expo/RECIPES.md +385 -0
  33. package/.claude/skills/animate-expo/SKILL.md +264 -0
  34. package/.claude/skills/animate-expo/agents/openai.yaml +5 -0
  35. package/.claude/skills/animation-performance/SKILL.md +223 -0
  36. package/.claude/skills/animation-performance/agents/openai.yaml +5 -0
  37. package/.claude/skills/apple-design/SKILL.md +291 -0
  38. package/.claude/skills/apple-design/agents/openai.yaml +5 -0
  39. package/.claude/skills/arch-api/SKILL.md +291 -0
  40. package/.claude/skills/arch-api/agents/openai.yaml +3 -0
  41. package/.claude/skills/arch-api/references/common.md +174 -0
  42. package/.claude/skills/arch-api/references/contract.md +289 -0
  43. package/.claude/skills/arch-api/references/domain.md +301 -0
  44. package/.claude/skills/arch-api/references/endpoints.md +184 -0
  45. package/.claude/skills/arch-api/references/review.md +228 -0
  46. package/.claude/skills/arch-api/references/security.md +151 -0
  47. package/.claude/skills/arch-app/SKILL.md +278 -0
  48. package/.claude/skills/arch-app/agents/openai.yaml +3 -0
  49. package/.claude/skills/arch-app/references/navigation-session.md +257 -0
  50. package/.claude/skills/arch-app/references/review.md +155 -0
  51. package/.claude/skills/arch-app/references/screens.md +214 -0
  52. package/.claude/skills/arch-app/references/services.md +301 -0
  53. package/.claude/skills/arch-app/references/ui-mobile.md +124 -0
  54. package/.claude/skills/arch-db/SKILL.md +181 -0
  55. package/.claude/skills/arch-db/agents/openai.yaml +3 -0
  56. package/.claude/skills/arch-db/references/indexes-queries.md +251 -0
  57. package/.claude/skills/arch-db/references/migrations.md +191 -0
  58. package/.claude/skills/arch-db/references/modeling.md +214 -0
  59. package/.claude/skills/arch-db/references/mysql.md +262 -0
  60. package/.claude/skills/arch-db/references/pooling-ops.md +112 -0
  61. package/.claude/skills/arch-db/references/review.md +143 -0
  62. package/.claude/skills/arch-db/references/transactions-locks.md +141 -0
  63. package/.claude/skills/arch-web/SKILL.md +307 -0
  64. package/.claude/skills/arch-web/agents/openai.yaml +3 -0
  65. package/.claude/skills/arch-web/references/auth-session-env.md +165 -0
  66. package/.claude/skills/arch-web/references/blocks.md +198 -0
  67. package/.claude/skills/arch-web/references/cache.md +124 -0
  68. package/.claude/skills/arch-web/references/review.md +142 -0
  69. package/.claude/skills/arch-web/references/services.md +297 -0
  70. package/.claude/skills/arch-web/references/tests.md +159 -0
  71. package/.claude/skills/arch-web/references/ui-forms.md +143 -0
  72. package/.claude/skills/break-ui/CATALOG.md +135 -0
  73. package/.claude/skills/break-ui/SKILL.md +176 -0
  74. package/.claude/skills/break-ui/agents/openai.yaml +5 -0
  75. package/.claude/skills/brief/SKILL.md +91 -0
  76. package/.claude/skills/brief/agents/openai.yaml +3 -0
  77. package/.claude/skills/diagnosing-bugs/SKILL.md +138 -0
  78. package/.claude/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  79. package/.claude/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  80. package/.claude/skills/emil-design-eng/SKILL.md +675 -0
  81. package/.claude/skills/emil-design-eng/agents/openai.yaml +5 -0
  82. package/.claude/skills/find-animation-opportunities/SKILL.md +141 -0
  83. package/.claude/skills/find-animation-opportunities/agents/openai.yaml +5 -0
  84. package/.claude/skills/graphify/.graphify_version +1 -0
  85. package/.claude/skills/graphify/SKILL.md +742 -0
  86. package/.claude/skills/graphify/agents/openai.yaml +3 -0
  87. package/.claude/skills/graphify/references/add-watch.md +56 -0
  88. package/.claude/skills/graphify/references/exports.md +91 -0
  89. package/.claude/skills/graphify/references/extraction-spec.md +70 -0
  90. package/.claude/skills/graphify/references/github-and-merge.md +46 -0
  91. package/.claude/skills/graphify/references/hooks.md +33 -0
  92. package/.claude/skills/graphify/references/query.md +317 -0
  93. package/.claude/skills/graphify/references/transcribe.md +52 -0
  94. package/.claude/skills/graphify/references/update.md +221 -0
  95. package/.claude/skills/grill-me/SKILL.md +7 -0
  96. package/.claude/skills/grill-me/agents/openai.yaml +5 -0
  97. package/.claude/skills/grill-with-docs/SKILL.md +64 -0
  98. package/.claude/skills/grill-with-docs/agents/openai.yaml +5 -0
  99. package/.claude/skills/grilling/SKILL.md +30 -0
  100. package/.claude/skills/grilling/agents/openai.yaml +3 -0
  101. package/.claude/skills/handoff/SKILL.md +28 -0
  102. package/.claude/skills/handoff/agents/openai.yaml +5 -0
  103. package/.claude/skills/impeccable/SKILL.md +89 -0
  104. package/.claude/skills/impeccable/agents/openai.yaml +5 -0
  105. package/.claude/skills/impeccable/reference/adapt.md +318 -0
  106. package/.claude/skills/impeccable/reference/adapt.native.md +58 -0
  107. package/.claude/skills/impeccable/reference/android.md +46 -0
  108. package/.claude/skills/impeccable/reference/animate.md +89 -0
  109. package/.claude/skills/impeccable/reference/audit.md +137 -0
  110. package/.claude/skills/impeccable/reference/audit.native.md +139 -0
  111. package/.claude/skills/impeccable/reference/bolder.md +33 -0
  112. package/.claude/skills/impeccable/reference/clarify.md +94 -0
  113. package/.claude/skills/impeccable/reference/colorize.md +86 -0
  114. package/.claude/skills/impeccable/reference/component-review.md +63 -0
  115. package/.claude/skills/impeccable/reference/craft-floor.md +44 -0
  116. package/.claude/skills/impeccable/reference/craft.md +5 -0
  117. package/.claude/skills/impeccable/reference/critique.md +809 -0
  118. package/.claude/skills/impeccable/reference/degraded/asset-producer.md +42 -0
  119. package/.claude/skills/impeccable/reference/degraded/documenter.md +24 -0
  120. package/.claude/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
  121. package/.claude/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
  122. package/.claude/skills/impeccable/reference/delight.md +70 -0
  123. package/.claude/skills/impeccable/reference/distill.md +111 -0
  124. package/.claude/skills/impeccable/reference/doctor.md +54 -0
  125. package/.claude/skills/impeccable/reference/document.md +416 -0
  126. package/.claude/skills/impeccable/reference/extract.md +69 -0
  127. package/.claude/skills/impeccable/reference/generate.md +101 -0
  128. package/.claude/skills/impeccable/reference/harden.md +345 -0
  129. package/.claude/skills/impeccable/reference/hooks.md +113 -0
  130. package/.claude/skills/impeccable/reference/init.md +131 -0
  131. package/.claude/skills/impeccable/reference/ios.md +51 -0
  132. package/.claude/skills/impeccable/reference/layout.md +84 -0
  133. package/.claude/skills/impeccable/reference/live-setup.md +104 -0
  134. package/.claude/skills/impeccable/reference/live.md +325 -0
  135. package/.claude/skills/impeccable/reference/mode-operate.md +21 -0
  136. package/.claude/skills/impeccable/reference/mode-persuade.md +19 -0
  137. package/.claude/skills/impeccable/reference/mode-read.md +21 -0
  138. package/.claude/skills/impeccable/reference/new-work.md +154 -0
  139. package/.claude/skills/impeccable/reference/onboard.md +234 -0
  140. package/.claude/skills/impeccable/reference/operate.md +61 -0
  141. package/.claude/skills/impeccable/reference/optimize.md +258 -0
  142. package/.claude/skills/impeccable/reference/overdrive.md +127 -0
  143. package/.claude/skills/impeccable/reference/polish.md +105 -0
  144. package/.claude/skills/impeccable/reference/quieter.md +99 -0
  145. package/.claude/skills/impeccable/reference/region-map.md +26 -0
  146. package/.claude/skills/impeccable/reference/routing.md +24 -0
  147. package/.claude/skills/impeccable/reference/shape.md +59 -0
  148. package/.claude/skills/impeccable/reference/typeset.md +80 -0
  149. package/.claude/skills/impeccable/reference/visualize.md +47 -0
  150. package/.claude/skills/impeccable/scripts/VERSION +1 -0
  151. package/.claude/skills/impeccable/scripts/command-metadata.json +98 -0
  152. package/.claude/skills/impeccable/scripts/data/font-index-failures.json +121 -0
  153. package/.claude/skills/impeccable/scripts/data/font-index.json +1 -0
  154. package/.claude/skills/impeccable/scripts/impeccable +206 -0
  155. package/.claude/skills/impeccable/scripts/impeccable.cmd +214 -0
  156. package/.claude/skills/impeccable/scripts/live-browser-dom.js +281 -0
  157. package/.claude/skills/impeccable/scripts/live-browser-ignores.js +242 -0
  158. package/.claude/skills/impeccable/scripts/live-browser-session.js +148 -0
  159. package/.claude/skills/impeccable/scripts/live-browser.js +13532 -0
  160. package/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  161. package/.claude/skills/improve-animations/AUDIT.md +115 -0
  162. package/.claude/skills/improve-animations/PLAN-TEMPLATE.md +73 -0
  163. package/.claude/skills/improve-animations/SKILL.md +110 -0
  164. package/.claude/skills/improve-animations/agents/openai.yaml +5 -0
  165. package/.claude/skills/mobile-native/SKILL.md +311 -0
  166. package/.claude/skills/mobile-native/agents/openai.yaml +3 -0
  167. package/.claude/skills/orchestrate/SKILL.md +181 -0
  168. package/.claude/skills/orchestrate/agents/openai.yaml +3 -0
  169. package/.claude/skills/pick-ui-library/SKILL.md +85 -0
  170. package/.claude/skills/pick-ui-library/agents/openai.yaml +5 -0
  171. package/.claude/skills/ponytail/SKILL.md +52 -0
  172. package/.claude/skills/ponytail/agents/openai.yaml +3 -0
  173. package/.claude/skills/ponytail-audit/SKILL.md +103 -0
  174. package/.claude/skills/ponytail-audit/agents/openai.yaml +3 -0
  175. package/.claude/skills/ponytail-debt/SKILL.md +44 -0
  176. package/.claude/skills/ponytail-debt/agents/openai.yaml +3 -0
  177. package/.claude/skills/ponytail-review/SKILL.md +101 -0
  178. package/.claude/skills/ponytail-review/agents/openai.yaml +3 -0
  179. package/.claude/skills/postgres-best-practices/SKILL.md +42 -0
  180. package/.claude/skills/postgres-best-practices/agents/openai.yaml +3 -0
  181. package/.claude/skills/postgres-best-practices/references/backup-restore.md +372 -0
  182. package/.claude/skills/postgres-best-practices/references/bulk-loading.md +315 -0
  183. package/.claude/skills/postgres-best-practices/references/connection-pooling.md +310 -0
  184. package/.claude/skills/postgres-best-practices/references/hot-standby.md +221 -0
  185. package/.claude/skills/postgres-best-practices/references/indexing.md +318 -0
  186. package/.claude/skills/postgres-best-practices/references/logical-replication.md +610 -0
  187. package/.claude/skills/postgres-best-practices/references/major-version-upgrades.md +334 -0
  188. package/.claude/skills/postgres-best-practices/references/performance-diagnostics.md +553 -0
  189. package/.claude/skills/postgres-best-practices/references/query-optimization.md +294 -0
  190. package/.claude/skills/postgres-best-practices/references/query-patterns.md +566 -0
  191. package/.claude/skills/postgres-best-practices/references/schema-design.md +362 -0
  192. package/.claude/skills/postgres-best-practices/references/security-roles.md +489 -0
  193. package/.claude/skills/postgres-best-practices/references/transaction-isolation.md +344 -0
  194. package/.claude/skills/project-docs/SKILL.md +330 -0
  195. package/.claude/skills/project-docs/agents/openai.yaml +3 -0
  196. package/.claude/skills/prototype/PICKER.md +197 -0
  197. package/.claude/skills/prototype/SKILL.md +98 -0
  198. package/.claude/skills/prototype/agents/openai.yaml +5 -0
  199. package/.claude/skills/retro/SKILL.md +43 -0
  200. package/.claude/skills/retro/agents/openai.yaml +5 -0
  201. package/.claude/skills/review/SKILL.md +74 -0
  202. package/.claude/skills/review/agents/openai.yaml +3 -0
  203. package/.claude/skills/review/references/smells.md +23 -0
  204. package/.claude/skills/review-animations/SKILL.md +120 -0
  205. package/.claude/skills/review-animations/STANDARDS.md +187 -0
  206. package/.claude/skills/review-animations/agents/openai.yaml +5 -0
  207. package/.claude/skills/tdd/SKILL.md +38 -0
  208. package/.claude/skills/tdd/agents/openai.yaml +3 -0
  209. package/.claude/skills/tdd/mocking.md +59 -0
  210. package/.claude/skills/tdd/tests.md +77 -0
  211. package/.claude/skills/triage/SKILL.md +58 -0
  212. package/.claude/skills/triage/agents/openai.yaml +3 -0
  213. package/.claude/skills/ui-ux-pro-max/SKILL.md +378 -0
  214. package/.claude/skills/ui-ux-pro-max/agents/openai.yaml +5 -0
  215. package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
  216. package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
  217. package/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
  218. package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
  219. package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
  220. package/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  221. package/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  222. package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  223. package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  224. package/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  225. package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  226. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  227. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  228. package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  229. package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  230. package/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  231. package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  232. package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  233. package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  234. package/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
  235. package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
  236. package/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  237. package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  238. package/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  239. package/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
  240. package/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  241. package/.claude/skills/ui-ux-pro-max/scripts/search.py +114 -0
  242. package/.claude/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  243. package/.claude/skills/writing-for-agents/SKILL.md +81 -0
  244. package/.claude/skills/writing-for-agents/agents/openai.yaml +3 -0
  245. package/.worktreeinclude +3 -0
  246. package/AGENTS.md +44 -0
  247. package/README.md +14 -2
  248. package/VERSION +1 -0
  249. package/bin/agents.mjs +45 -0
  250. package/docs/adr/README.md +31 -0
  251. package/docs/brief-template.md +3 -0
  252. package/docs/plans/README.md +73 -0
  253. package/package.json +46 -4
  254. package/scripts/bootstrap.mjs +188 -0
  255. package/scripts/check-catalog.mjs +43 -0
  256. package/scripts/skills-update.mjs +51 -0
  257. package/skills-lock.json +269 -0
  258. 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.