{"id":"8cf0aa9a-6165-4e02-93db-a5745956fe7d","shortId":"hmHCfx","kind":"skill","title":"postgresql","tagline":">-","description":"# PostgreSQL\n\n## Data Type Defaults\n\n| Need | Use | Avoid |\n|------|-----|-------|\n| Primary key | `BIGINT GENERATED ALWAYS AS IDENTITY` | `SERIAL`, `BIGSERIAL` |\n| Timestamps | `TIMESTAMPTZ` | `TIMESTAMP` (loses timezone) |\n| Text | `TEXT` | `VARCHAR(n)` unless constraint needed |\n| Money | `NUMERIC(precision, scale)` | `MONEY`, `FLOAT` |\n| Boolean | `BOOLEAN` with `NOT NULL DEFAULT` | nullable booleans |\n| JSON | `JSONB` | `JSON` (no indexing), text JSON |\n| UUID | `gen_random_uuid()` (PG13+) | `uuid-ossp` extension |\n| IP addresses | `INET` / `CIDR` | text |\n| Ranges | `TSTZRANGE`, `INT4RANGE`, etc. | pair of columns |\n\n## Schema Rules\n\n- Every FK column gets an index (PG does NOT auto-create these)\n- `NOT NULL` on every column unless NULL has business meaning\n- `CHECK` constraints for domain rules at DB level\n- `EXCLUDE` constraints for range overlaps: `EXCLUDE USING gist (room WITH =, during WITH &&)`\n- Default `created_at TIMESTAMPTZ NOT NULL DEFAULT now()`\n- Separate `updated_at` with trigger, never trust app layer alone\n- Use `BIGINT` PKs -- cheaper JOINs than UUID, better index locality\n- Safe migrations: `CREATE INDEX CONCURRENTLY`, add columns with `DEFAULT` (instant add). Never `ALTER TYPE` on large tables in-place.\n- `NULLS NOT DISTINCT` on unique indexes (PG15+) -- treats NULLs as equal for uniqueness\n- Revoke default public schema access: `REVOKE ALL ON SCHEMA public FROM public`\n\n## Migration Safety\n\n**Core rules:**\n- Every schema change is a migration. No ad-hoc DDL in production.\n- Migrations are immutable once deployed -- never edit a migration that has run in any shared environment.\n- Schema migrations and data migrations are separate files. Schema changes are fast and transactional; data backfills are slow and may need batching.\n- Forward-only in production. Rollback = a new forward migration that reverses the change.\n\n**Expand-contract pattern** for zero-downtime renames and removals:\n\n1. **Expand**: add the new column/table, backfill data, update writes to populate both old and new\n2. **Migrate**: switch reads to the new column/table, verify in production\n3. **Contract**: remove the old column/table in a later deploy\n\nNever rename or remove a column in a single migration -- callers reading the old name will break between deploy and code rollout.\n\n**Dangerous operations:**\n- `NOT NULL` without a `DEFAULT` on an existing table locks and rewrites every row. Add the column nullable first, backfill, then add the constraint.\n- `CREATE INDEX` (without `CONCURRENTLY`) locks writes for the duration. Always use `CONCURRENTLY`, which cannot run inside a transaction block -- keep it in its own migration.\n- Large data backfills: batch with `FOR UPDATE SKIP LOCKED` to avoid locking the entire table:\n\n```sql\nUPDATE target SET new_col = compute(old_col)\nWHERE id IN (\n  SELECT id FROM target\n  WHERE new_col IS NULL\n  LIMIT 1000\n  FOR UPDATE SKIP LOCKED\n);\n```\n\nRun in a loop until zero rows affected.\n\n**Full-replace clobber on read-modify-write loops.** A migration that loops `SELECT col → mutate in app → UPDATE SET col = new_full_value WHERE id = ?` silently drops concurrent writes that landed between SELECT and UPDATE. Any column written by live traffic is exposed: `jsonb` documents, comma-separated tag fields, denormalized counters, JSON-encoded attribute blobs. Mitigations, in order of preference:\n\n- **In-place atomic update** when the edit is expressible as SQL: `UPDATE t SET col = jsonb_set(col, '{path}', :value) WHERE ...`, or `UPDATE t SET tags = array_append(tags, :tag) WHERE ...` — no read-modify-write window.\n- **Row-level lock during the loop:** wrap each iteration in a transaction, `SELECT ... WHERE id = ? FOR UPDATE`, then mutate and write. Cheaper to author, accepts more lock contention.\n- **Compare-and-swap retry:** include the original snapshot in `WHERE col = :original_value`, check the affected-row count; on 0, re-read and retry. Robust under contention, requires explicit retry-loop handling.\n\nDefault chunked decode-encode loops are only safe during a maintenance window with writes blocked. ORM \"chunkById + load + mutate + save\" patterns hit this same trap.\n\n## Index Strategy\n\n| Type | Use When |\n|------|----------|\n| B-tree (default) | Equality, range, sorting, `LIKE 'prefix%'` |\n| GIN | JSONB (`@>`, `?`, `?&`), arrays, full-text (`tsvector`) |\n| GiST | Geometry, ranges, full-text (smaller but slower than GIN) |\n| BRIN | Large tables with natural ordering (timestamps, serial IDs) |\n\n**Index rules:**\n- Composite: most selective column first, max 3-4 columns\n- Partial: `WHERE status = 'active'` -- smaller, faster\n- Covering: `INCLUDE (col)` -- avoids heap lookup\n- Expression: `ON (lower(email))` -- for function-based WHERE\n- `fillfactor = 70-90` on write-heavy tables -- reserves space for HOT updates, reducing index bloat\n- Drop unused indexes (only after one full business cycle since last restart -- check `pg_stat_database.stats_reset` first, otherwise you may drop a primary key on a freshly restarted DB or read replica): `SELECT * FROM pg_stat_user_indexes WHERE idx_scan = 0`\n\n**Detect unindexed foreign keys:**\n```sql\nSELECT conrelid::regclass, a.attname\nFROM pg_constraint c\nJOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = ANY(c.conkey)\nWHERE c.contype = 'f'\n  AND NOT EXISTS (\n    SELECT 1 FROM pg_index i\n    WHERE i.indrelid = c.conrelid AND a.attnum = ANY(i.indkey)\n  );\n```\n\n## JSONB Patterns\n\n```sql\n-- GIN index for containment queries\nCREATE INDEX ON items USING gin (metadata);\nSELECT * FROM items WHERE metadata @> '{\"status\": \"active\"}';\n\n-- Expression index for specific key access\nCREATE INDEX ON items ((metadata->>'category'));\nSELECT * FROM items WHERE metadata->>'category' = 'electronics';\n```\n\nPrefer typed columns over JSONB for frequently queried, well-structured data. Use JSONB for truly dynamic/variable attributes.\n\nUse `jsonb_path_ops` operator class for containment-only (`@>`) queries -- 2-3x smaller index. Use default `jsonb_ops` when key-existence (`?`, `?|`) is needed.\n\n**Delete operators:**\n\n| Operator | Operand | Behavior | Example |\n|----------|---------|----------|---------|\n| `-` | text | remove top-level key from object | `'{\"a\":1,\"b\":2}'::jsonb - 'a'` → `{\"b\":2}` |\n| `-` | text[] | remove multiple top-level keys | `'{\"a\":1,\"b\":2}'::jsonb - ARRAY['a','b']` → `{}` |\n| `-` | integer | remove array element by index | `'[1,2,3]'::jsonb - 1` → `[1,3]` |\n| `#-` | text[] | remove value at nested path | `'{\"a\":{\"b\":1}}'::jsonb #- '{a,b}'` → `{\"a\":{}}` |\n\nCommon mistakes:\n\n- `col - 'a,b'` treats `'a,b'` as a single key name (no-op against a normally-structured document — the comma isn't a path separator).\n- `col - 'a' - 'b'` first removes the entire `a` subtree before attempting `- 'b'` on the result (data loss of `a.*`, then a no-op).\n- `jsonb_set(col, '{a,b}', 'null'::jsonb)` sets the value to JSON `null` rather than removing the key — strict \"key absent\" checks downstream then fail. Worse: `jsonb_set(col, '{a,b}', NULL)` with a bare SQL `NULL` makes the STRICT function return SQL `NULL`, clobbering the entire column on update. To delete the key, use `#-`; to set it explicitly to JSON null, use `'null'::jsonb` (and know that's distinct from absence).\n\nFor nested deletes, use `#-` with a text-array path. Verify with one round-tripped row of the worst-case shape before committing the migration: `SELECT col #- '{a,b}' FROM t WHERE id = ? LIMIT 1`, then confirm the key is gone (not present-as-null, no sibling data loss).\n\n## Row-Level Security (RLS)\n\n```sql\nALTER TABLE orders ENABLE ROW LEVEL SECURITY;\nALTER TABLE orders FORCE ROW LEVEL SECURITY;  -- applies to table owner too\n\n-- Set session context (generic, no extensions needed)\nSET app.current_user_id = '123';\n\nCREATE POLICY orders_user_policy ON orders\n  FOR ALL\n  USING (user_id = current_setting('app.current_user_id')::bigint);\n```\n\n**Performance:** Policy expressions evaluate per row. Wrap function calls in a scalar subquery so PG evaluates once and caches:\n\n```sql\n-- BAD: called per row\nUSING (get_current_user() = user_id)\n-- GOOD: evaluated once, cached\nUSING ((SELECT get_current_user()) = user_id)\n```\n\nAlways index columns referenced in RLS policies. For complex multi-table checks, use `SECURITY DEFINER` helper functions.\n\n## Query Optimization\n\n- Always `EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)` before optimizing\n- Use `pg_stat_statements` for slow-query detection and `pg_stat_user_tables` for bloat (see Detection queries below for the full SQL)\n- Sequential scan on large table -> add index or check `WHERE` for function wrapping\n- High `rows removed by filter` -> index doesn't match predicate\n- CTEs are inlined by default; use `MATERIALIZED`/`NOT MATERIALIZED` hints to control optimization\n- Prefer `EXISTS` over `IN` for correlated subqueries\n- Use `LATERAL JOIN` when subquery needs outer row reference\n- Cursor pagination (`WHERE id > $last ORDER BY id LIMIT $n`) over `OFFSET`\n- Approximate row counts: `SELECT reltuples FROM pg_class WHERE relname = 'table'` -- avoids full `count(*)` on large tables\n- Materialized views for expensive aggregations: `REFRESH MATERIALIZED VIEW CONCURRENTLY` (needs unique index). Schedule refresh, not per-query.\n\n## Concurrency Patterns\n\nSee [concurrency-patterns.md](./references/concurrency-patterns.md) for UPSERT, deadlock prevention, N+1 elimination, batch inserts, and queue processing with SKIP LOCKED.\n\n## Partitioning\n\nUse when table exceeds ~100M rows or needs TTL purge:\n- `RANGE` -- time-series (by month/year), most common\n- `LIST` -- categorical (by region, tenant)\n- `HASH` -- even distribution when no natural key\n\nPartition key must be in every unique/PK constraint. Create indexes on partitions, not parent.\n\n## Transactions & Locking\n\n- Keep transactions short -- long txns block vacuum and bloat tables\n- Advisory locks for application-level mutual exclusion: `pg_advisory_xact_lock(key)`\n- Non-blocking alternative: `pg_try_advisory_lock(key)` -- returns false instead of waiting\n- Check blocked queries: `SELECT * FROM pg_stat_activity WHERE wait_event_type = 'Lock'`\n- Monitor deadlocks: `SELECT deadlocks FROM pg_stat_database WHERE datname = current_database()`\n\n## Full-Text Search\n\nSee [full-text-search.md](./references/full-text-search.md) for weighted tsvector setup, query syntax, highlighting, and when to use PG full-text vs external search.\n\n## Connection Pooling\n\nAlways pool in production. Direct connections cost ~10MB each.\n- PgBouncer in `transaction` mode for most workloads\n- `statement` mode if no session-level features (prepared statements, temp tables, advisory locks)\n\n**Prepared statement caveat:** Named prepared statements are bound to a specific connection. In transaction-mode pooling, the next request may hit a different connection. Use unnamed/extended-query-protocol statements (most ORMs default to this), or deallocate immediately after use.\n\n## Operations\n\nSee [operations.md](./references/operations.md) for performance tuning, maintenance/monitoring, WAL, replication, and backup/recovery.\n\n## Vector Search (pgvector)\n\n```sql\nCREATE EXTENSION vector;\nALTER TABLE items ADD COLUMN embedding vector(1536);  -- match your model's output dimensions\n\n-- HNSW: better recall, higher memory. Default choice.\nCREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);\n\n-- IVFFlat: lower memory for large datasets. Set lists = sqrt(row_count).\nCREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 1000);\n```\n\nAlways filter BEFORE vector search (use partial indexes or CTEs with pre-filtered rows). Distance operators: `<=>` cosine, `<->` L2, `<#>` inner product.\n\n## Anti-Patterns\n\n| Anti-Pattern | Fix |\n|-------------|-----|\n| `SELECT *` | List needed columns |\n| N+1 queries in application loop | Use `JOIN`, `IN`, or batch fetch |\n| `OFFSET` for pagination on large tables | Cursor pagination: `WHERE id > $last ORDER BY id LIMIT $n` |\n| `count(*)` on large tables | Approximate: `SELECT reltuples FROM pg_class WHERE relname = 'table'` |\n| Nullable booleans | `NOT NULL DEFAULT false` -- three-valued logic causes subtle bugs |\n| Missing FK indexes | See detection query in Index Strategy above |\n| `ORDER BY RANDOM()` | Use `TABLESAMPLE` or application-side shuffle |\n\n**Detection queries:**\n\n```sql\n-- Slow queries (requires pg_stat_statements)\nSELECT query, mean_exec_time, calls\nFROM pg_stat_statements\nWHERE mean_exec_time > 100\nORDER BY mean_exec_time DESC LIMIT 20;\n\n-- Table bloat (dead tuples awaiting vacuum)\nSELECT relname, n_dead_tup, last_vacuum, last_autovacuum\nFROM pg_stat_user_tables\nWHERE n_dead_tup > 10000\nORDER BY n_dead_tup DESC;\n\n-- Unused indexes (candidates for removal)\nSELECT schemaname, relname, indexrelname, idx_scan\nFROM pg_stat_user_indexes\nWHERE idx_scan = 0 AND indexrelname NOT LIKE '%_pkey'\nORDER BY pg_relation_size(indexrelid) DESC;\n```\n\n## Verify\n\nRun `EXPLAIN (ANALYZE, BUFFERS)` on changed queries. Confirm no sequential scans on large tables and no unindexed FK columns before declaring done.","tags":["postgresql","skills","iliaal","agent-skills","ai-coding-assistant","ai-tools","claude-code"],"capabilities":["skill","source-iliaal","skill-postgresql","topic-agent-skills","topic-ai-coding-assistant","topic-ai-tools","topic-claude-code","topic-skills"],"categories":["ai-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/iliaal/ai-skills/postgresql","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add iliaal/ai-skills","source_repo":"https://github.com/iliaal/ai-skills","install_from":"skills.sh"}},"qualityScore":"0.456","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 13 github stars · SKILL.md body (13,039 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:03.211Z","embedding":null,"createdAt":"2026-05-09T01:05:36.241Z","updatedAt":"2026-05-18T19:07:03.211Z","lastSeenAt":"2026-05-18T19:07:03.211Z","tsv":"'+1':1378,1699 '-3':867 '-4':673 '-90':698 '/references/concurrency-patterns.md':1372 '/references/full-text-search.md':1503 '/references/operations.md':1595 '0':582,752,1854 '1':270,784,896,911,924,928,929,939,1105 '100':1795 '1000':417,1665 '10000':1828 '100m':1393 '10mb':1531 '123':1157 '1536':1618 '2':286,866,898,902,913,925 '20':1803 '3':297,672,926,930 '70':697 'a.attname':761 'a.attnum':774,793 'a.attrelid':771 'absenc':1068 'absent':1017 'accept':557 'access':182,823 'activ':678,817,1479 'ad':202 'ad-hoc':201 'add':150,155,272,345,352,1274,1614 'address':61 'advisori':1445,1454,1464,1552 'affect':429,578 'affected-row':577 'aggreg':1354 'alon':134 'alter':157,1127,1134,1611 'altern':1461 'alway':13,364,1217,1237,1524,1666 'analyz':1239,1870 'anti':1688,1691 'anti-pattern':1687,1690 'app':132,448 'app.current':1154,1172 'append':522 'appli':1141 'applic':1449,1702,1769 'application-level':1448 'application-sid':1768 'approxim':1333,1730 'array':521,639,915,920,1077 'atom':497 'attempt':983 'attribut':487,768,854 'author':556 'auto':84 'auto-cr':83 'autovacuum':1818 'avoid':8,390,684,1344 'await':1808 'b':629,897,901,912,917,938,942,948,951,975,984,1001,1027,1099 'b-tree':628 'backfil':238,276,350,382 'backup/recovery':1603 'bad':1196 'bare':1031 'base':694 'batch':244,383,1380,1708 'behavior':885 'better':142,1626 'bigint':11,136,1175 'bigseri':17 'bloat':711,1260,1443,1805 'blob':488 'block':373,612,1440,1460,1473 'boolean':36,37,43,1740 'bound':1561 'break':323 'brin':655 'buffer':1240,1871 'bug':1751 'busi':95,719 'c':765 'c.conkey':776 'c.conrelid':772,791 'c.contype':778 'cach':1194,1209 'call':1184,1197,1786 'caller':317 'candid':1837 'cannot':368 'case':1090 'categor':1408 'categori':829,835 'caus':1749 'caveat':1556 'chang':196,232,258,1873 'cheaper':138,554 'check':97,575,724,1018,1229,1277,1472 'choic':1631 'chunk':598 'chunkbyid':614 'cidr':63 'class':860,1340,1735 'clobber':433,1041 'code':327 'col':400,403,413,445,451,509,512,572,683,946,973,999,1025,1097 'column':71,76,91,151,312,347,468,669,674,839,1044,1219,1615,1697,1886 'column/table':275,293,302 'comma':478,967 'comma-separ':477 'commit':1093 'common':944,1406 'compar':562 'compare-and-swap':561 'complex':1225 'composit':666 'comput':401 'concurr':149,358,366,459,1358,1368 'concurrency-patterns.md':1371 'confirm':1107,1875 'connect':1522,1529,1565,1578 'conrelid':759 'constraint':28,98,106,354,764,1426 'contain':802,863 'containment-on':862 'content':560,590 'context':1148 'contract':261,298 'control':1303 'core':192 'correl':1310 'cosin':1640,1661,1683 'cost':1530 'count':580,1335,1346,1652,1726 'counter':483 'cover':681 'creat':85,118,147,355,804,824,1158,1427,1608,1632,1653 'ctes':1292,1675 'current':1170,1202,1213,1495 'cursor':1321,1716 'cycl':720 'danger':329 'data':3,226,237,277,381,848,988,1119 'databas':1492,1496 'dataset':1647 'datnam':1494 'db':103,739 'ddl':204 'dead':1806,1813,1826,1832 'deadlock':1375,1486,1488 'dealloc':1588 'declar':1888 'decod':600 'decode-encod':599 'default':5,41,117,123,153,179,335,597,631,872,1296,1584,1630,1743 'defin':1232 'delet':881,1048,1071 'denorm':482 'deploy':211,306,325 'desc':1801,1834,1866 'detect':753,1253,1262,1756,1772 'differ':1577 'dimens':1624 'direct':1528 'distanc':1681 'distinct':167,1066 'distribut':1414 'document':476,965 'doesn':1288 'domain':100 'done':1889 'downstream':1019 'downtim':266 'drop':458,712,731 'durat':363 'dynamic/variable':853 'edit':213,501 'electron':836 'element':921 'elimin':1379 'email':690 'embed':1616,1638,1659 'enabl':1130 'encod':486,601 'entir':393,979,1043 'environ':222 'equal':175,632 'etc':68 'evalu':1179,1191,1207 'even':1413 'event':1482 'everi':74,90,194,343,1424 'exampl':886 'exceed':1392 'exclud':105,110 'exclus':1452 'exec':1784,1793,1799 'exist':338,782,878,1306 'expand':260,271 'expand-contract':259 'expens':1353 'explain':1238,1869 'explicit':592,1055 'expos':474 'express':503,687,818,1178 'extens':59,1151,1609 'extern':1520 'f':779 'fail':1021 'fals':1468,1744 'fast':234 'faster':680 'featur':1547 'fetch':1709 'field':481 'file':230 'fillfactor':696 'filter':1286,1667,1679 'first':349,670,727,976 'fix':1693 'fk':75,1753,1885 'float':35 'forc':1137 'foreign':755 'format':1241 'forward':246,253 'forward-on':245 'frequent':843 'fresh':737 'full':431,453,641,648,718,1267,1345,1498,1517 'full-replac':430 'full-text':640,647,1497,1516 'full-text-search.md':1502 'function':693,1037,1183,1234,1280 'function-bas':692 'gen':52 'generat':12 'generic':1149 'geometri':645 'get':77,1201,1212 'gin':637,654,799,809 'gist':112,644 'gone':1111 'good':1206 'handl':596 'hash':1412 'heap':685 'heavi':702 'helper':1233 'high':1282 'higher':1628 'highlight':1510 'hint':1301 'hit':619,1575 'hnsw':1625,1637 'hoc':203 'hot':707 'i.indkey':795 'i.indrelid':790 'id':405,408,456,547,663,1103,1156,1169,1174,1205,1216,1324,1328,1719,1723 'ident':15 'idx':750,1844,1852 'immedi':1589 'immut':209 'in-plac':162,494 'includ':566,682 'index':48,79,143,148,170,356,623,664,710,714,748,787,800,805,819,825,870,923,1218,1275,1287,1361,1428,1633,1654,1673,1754,1759,1836,1850 'indexrelid':1865 'indexrelnam':1843,1856 'inet':62 'inlin':1294 'inner':1685 'insert':1381 'insid':370 'instant':154 'instead':1469 'int4range':67 'integ':918 'ip':60 'isn':968 'item':807,813,827,832,1613,1635,1656 'iter':541 'ivfflat':1642,1658 'join':139,766,1314,1705 'json':44,46,50,485,1008,1057 'json-encod':484 'jsonb':45,475,510,638,796,841,850,856,873,899,914,927,940,997,1003,1023,1061 'keep':374,1435 'key':10,734,756,822,877,892,909,955,1014,1016,1050,1109,1418,1420,1457,1466 'key-exist':876 'know':1063 'l2':1684 'land':462 'larg':160,380,656,1272,1348,1646,1714,1728,1880 'last':722,1325,1720,1815,1817 'later':305,1313 'layer':133 'level':104,534,891,908,1123,1132,1139,1450,1546 'like':635,1858 'limit':416,1104,1329,1724,1802 'list':1407,1649,1664,1695 'live':471 'load':615 'local':144 'lock':340,359,388,391,421,535,559,1387,1434,1446,1456,1465,1484,1553 'logic':1748 'long':1438 'lookup':686 'loop':425,439,443,538,595,602,1703 'lose':21 'loss':989,1120 'lower':689,1643 'mainten':608 'maintenance/monitoring':1599 'make':1034 'match':1290,1619 'materi':1298,1300,1350,1356 'max':671 'may':242,730,1574 'mean':96,1783,1792,1798 'memori':1629,1644 'metadata':810,815,828,834 'migrat':146,190,199,207,215,224,227,254,287,316,379,441,1095 'miss':1752 'mistak':945 'mitig':489 'mode':1536,1541,1569 'model':1621 'modifi':437,529 'money':30,34 'monitor':1485 'month/year':1404 'multi':1227 'multi-t':1226 'multipl':905 'must':1421 'mutat':446,551,616 'mutual':1451 'n':26,1330,1377,1698,1725,1812,1825,1831 'name':321,956,1557 'natur':659,1417 'need':6,29,243,880,1152,1317,1359,1396,1696 'nest':935,1070 'never':130,156,212,307 'new':252,274,285,292,399,412,452 'next':1572 'no-op':957,994 'non':1459 'non-block':1458 'normal':963 'normally-structur':962 'null':40,88,93,122,165,173,332,415,1002,1009,1028,1033,1040,1058,1060,1116,1742 'nullabl':42,348,1739 'numer':31 'object':894 'offset':1332,1710 'old':283,301,320,402 'one':717,1081 'op':858,874,959,996,1641,1662 'oper':330,859,882,883,1592,1682 'operand':884 'operations.md':1594 'optim':1236,1244,1304 'order':491,660,1129,1136,1160,1164,1326,1721,1762,1796,1829,1860 'origin':568,573 'orm':613,1583 'ossp':58 'otherwis':728 'outer':1318 'output':1623 'overlap':109 'owner':1144 'pagin':1322,1712,1717 'pair':69 'parent':1432 'partial':675,1672 'partit':1388,1419,1430 'path':513,857,936,971,1078 'pattern':262,618,797,1369,1689,1692 'per':1180,1198,1366 'per-queri':1365 'perform':1176,1597 'pg':80,745,763,767,786,1190,1246,1255,1339,1453,1462,1477,1490,1515,1734,1778,1788,1820,1847,1862 'pg13':55 'pg15':171 'pg_stat_database.stats':725 'pgbouncer':1533 'pgvector':1606 'pkey':1859 'pks':137 'place':164,496 'polici':1159,1162,1177,1223 'pool':1523,1525,1570 'popul':281 'postgresql':1,2 'pre':1678 'pre-filt':1677 'precis':32 'predic':1291 'prefer':493,837,1305 'prefix':636 'prepar':1548,1554,1558 'present':1114 'present-as-nul':1113 'prevent':1376 'primari':9,733 'process':1384 'product':206,249,296,1527,1686 'public':180,187,189 'purg':1398 'queri':803,844,865,1235,1252,1263,1367,1474,1508,1700,1757,1773,1776,1782,1874 'queue':1383 'random':53,1764 'rang':65,108,633,646,1399 'rather':1010 're':584 're-read':583 'read':289,318,436,528,585,741 'read-modify-writ':435,527 'recal':1627 'reduc':709 'refer':1320 'referenc':1220 'refresh':1355,1363 'regclass':760 'region':1410 'relat':1863 'relnam':1342,1737,1811,1842 'reltupl':1337,1732 'remov':269,299,310,888,904,919,932,977,1012,1284,1839 'renam':267,308 'replac':432 'replic':1601 'replica':742 'request':1573 'requir':591,1777 'reserv':704 'reset':726 'restart':723,738 'result':987 'retri':565,587,594 'retry-loop':593 'return':1038,1467 'revers':256 'revok':178,183 'rewrit':342 'rls':1125,1222 'robust':588 'rollback':250 'rollout':328 'room':113 'round':1083 'round-trip':1082 'row':344,428,533,579,1085,1122,1131,1138,1181,1199,1283,1319,1334,1394,1651,1680 'row-level':532,1121 'rule':73,101,193,665 'run':218,369,422,1868 'safe':145,605 'safeti':191 'save':617 'scalar':1187 'scale':33 'scan':751,1270,1845,1853,1878 'schedul':1362 'schema':72,181,186,195,223,231 'schemanam':1841 'search':1500,1521,1605,1670 'secur':1124,1133,1140,1231 'see':1261,1370,1501,1593,1755 'select':407,444,464,545,668,743,758,783,811,830,1096,1211,1336,1475,1487,1694,1731,1781,1810,1840 'separ':125,229,479,972 'sequenti':1269,1877 'seri':1402 'serial':16,662 'session':1147,1545 'session-level':1544 'set':398,450,508,511,519,998,1004,1024,1053,1146,1153,1171,1648 'setup':1507 'shape':1091 'share':221 'short':1437 'shuffl':1771 'sibl':1118 'side':1770 'silent':457 'sinc':721 'singl':315,954 'size':1864 'skill' 'skill-postgresql' 'skip':387,420,1386 'slow':240,1251,1775 'slow-queri':1250 'slower':652 'smaller':650,679,869 'snapshot':569 'sort':634 'source-iliaal' 'space':705 'specif':821,1564 'sql':395,505,757,798,1032,1039,1126,1195,1268,1607,1774 'sqrt':1650 'stat':746,1247,1256,1478,1491,1779,1789,1821,1848 'statement':1248,1540,1549,1555,1559,1581,1780,1790 'status':677,816 'strategi':624,1760 'strict':1015,1036 'structur':847,964 'subqueri':1188,1311,1316 'subtl':1750 'subtre':981 'swap':564 'switch':288 'syntax':1509 'tabl':161,339,394,657,703,1128,1135,1143,1228,1258,1273,1343,1349,1391,1444,1551,1612,1715,1729,1738,1804,1823,1881 'tablesampl':1766 'tag':480,520,523,524 'target':397,410 'temp':1550 'tenant':1411 'text':23,24,49,64,642,649,887,903,931,1076,1242,1499,1518 'text-array':1075 'three':1746 'three-valu':1745 'time':1401,1785,1794,1800 'time-seri':1400 'timestamp':18,20,661 'timestamptz':19,120 'timezon':22 'top':890,907 'top-level':889,906 'topic-agent-skills' 'topic-ai-coding-assistant' 'topic-ai-tools' 'topic-claude-code' 'topic-skills' 'traffic':472 'transact':236,372,544,1433,1436,1535,1568 'transaction-mod':1567 'trap':622 'treat':172,949 'tree':630 'tri':1463 'trigger':129 'trip':1084 'truli':852 'trust':131 'tstzrang':66 'tsvector':643,1506 'ttl':1397 'tune':1598 'tup':1814,1827,1833 'tupl':1807 'txns':1439 'type':4,158,625,838,1483 'unindex':754,1884 'uniqu':169,177,1360 'unique/pk':1425 'unless':27,92 'unnamed/extended-query-protocol':1580 'unus':713,1835 'updat':126,278,386,396,419,449,466,498,506,517,549,708,1046 'upsert':1374 'use':7,111,135,365,626,808,849,855,871,1051,1059,1072,1167,1200,1210,1230,1245,1297,1312,1389,1514,1579,1591,1636,1657,1671,1704,1765 'user':747,1155,1161,1168,1173,1203,1204,1214,1215,1257,1822,1849 'uuid':51,54,57,141 'uuid-ossp':56 'vacuum':1441,1809,1816 'valu':454,514,574,933,1006,1747 'varchar':25 'vector':1604,1610,1617,1639,1660,1669 'verifi':294,1079,1867 'view':1351,1357 'vs':1519 'wait':1471,1481 'wal':1600 'weight':1505 'well':846 'well-structur':845 'window':531,609 'without':333,357 'workload':1539 'wors':1022 'worst':1089 'worst-cas':1088 'wrap':539,1182,1281 'write':279,360,438,460,530,553,611,701 'write-heavi':700 'written':469 'x':868 'xact':1455 'zero':265,427 'zero-downtim':264","prices":[{"id":"2ac54031-a717-47ed-a44c-81b0f4dee8a9","listingId":"8cf0aa9a-6165-4e02-93db-a5745956fe7d","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"iliaal","category":"ai-skills","install_from":"skills.sh"},"createdAt":"2026-05-09T01:05:36.241Z"}],"sources":[{"listingId":"8cf0aa9a-6165-4e02-93db-a5745956fe7d","source":"github","sourceId":"iliaal/ai-skills/postgresql","sourceUrl":"https://github.com/iliaal/ai-skills/tree/master/skills/postgresql","isPrimary":false,"firstSeenAt":"2026-05-09T01:05:36.241Z","lastSeenAt":"2026-05-18T19:07:03.211Z"}],"details":{"listingId":"8cf0aa9a-6165-4e02-93db-a5745956fe7d","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"iliaal","slug":"postgresql","github":{"repo":"iliaal/ai-skills","stars":13,"topics":["agent-skills","ai-coding-assistant","ai-tools","claude-code","skills"],"license":"mit","html_url":"https://github.com/iliaal/ai-skills","pushed_at":"2026-05-16T13:15:17Z","description":"Curated collection of agent skills for AI coding assistants.","skill_md_sha":"87135e68c30ffc821feccd46a2004a3267e7a9bb","skill_md_path":"skills/postgresql/SKILL.md","default_branch":"master","skill_tree_url":"https://github.com/iliaal/ai-skills/tree/master/skills/postgresql"},"layout":"multi","source":"github","category":"ai-skills","frontmatter":{"name":"postgresql","description":">-"},"skills_sh_url":"https://skills.sh/iliaal/ai-skills/postgresql"},"updatedAt":"2026-05-18T19:07:03.211Z"}}