agentleFS
komlukkomluk/scaffolding/skills/database-optimization/SKILL.md

database-optimization

Skill16 starsChanged 4 days agoMITView on GitHub

Schema design, index strategy, migration safety, and query analysis. TRIGGER when: designing tables or indexes, writing a migration, or diagnosing a slow query. SKIP: writing ORM model code (use python-patterns); generic backend patterns (use python-patterns).

  • Deletes or force-pushes

3 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 6 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈6

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    ADD CONSTRAINT (with validation)

    line 46
  2. Distinctive:

    Use foreign keys and index them

    line 91
  3. Distinctive:

    Test with production-like data

    line 93
  4. Distinctive:

    Keep transactions short; avoid I/O inside transactions

    line 107
  5. Distinctive:

    Default isolation: Read Committed (usually sufficient)

    line 109
  6. Distinctive:

    Use Serializable only when phantom reads are unacceptable

    line 110
  7. Very specific:

    All models inherit from the shared declarative Base and follow these patterns:

    line 176
  8. Very specific:

    Safe pattern: Always include both upgrade() and downgrade() functions

    line 214

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Schema Design Principles

FormUse When
1NFAlways (atomic values)
2NFMost tables
3NFTransactional data
DenormalizedRead-heavy, reporting

Index Strategy

TypeUse Case
B-TreeDefault, range queries
HashExact match only
GIN (Postgres)Full-text, JSONB, arrays
PartialSubset of rows
CompositeMulti-column queries

Index type names vary by engine (e.g. GIN/GiST/BRIN are Postgres-specific; MySQL/SQLite expose a different set). Treat engine-specific rows as examples.

When to Index

  • Primary keys (automatic)
  • Foreign keys
  • WHERE clause columns
  • ORDER BY columns
  • JOIN columns

When NOT to Index

  • Low cardinality columns
  • Frequently updated columns
  • Small tables (< 1000 rows)

Migration Safety

Safe Operations

  • ADD COLUMN (nullable)
  • ADD INDEX CONCURRENTLY
  • CREATE TABLE
  • ADD CONSTRAINT (with validation)

Dangerous Operations

  • DROP COLUMN
  • RENAME COLUMN
  • ALTER COLUMN TYPE
  • DROP TABLE

Migration Checklist

  • Tested on production-like data
  • Rollback script ready
  • Estimated execution time
  • Lock impact assessed
  • Application compatibility verified

Query Analysis

Common Issues

IssueSymptomSolution
Missing indexSequential scanAdd index
N+1 queriesMany similar queriesEager loading
Over-fetchingSELECT *Select specific columns
No paginationLarge result setsAdd LIMIT/OFFSET
Cartesian joinExploding rowsFix JOIN conditions

Analysis Commands

Frontend

  • npm run build -- --analyze - Bundle analysis
  • lighthouse - Performance audit
  • Browser DevTools Performance tab

Backend (Python)

  • py-spy - CPU profiling
  • memory_profiler - Memory analysis
  • EXPLAIN ANALYZE - Query analysis

Best Practices

DO

  • Measure before optimizing
  • Design database for future scale
  • Document schema decisions
  • Use foreign keys and index them
  • Plan migrations carefully
  • Test with production-like data
  • Focus on user-impacting metrics

DON'T

  • Optimize prematurely
  • Guess at bottlenecks
  • Use SELECT *
  • Skip foreign keys
  • Over-index
  • Modify released migrations
  • Ignore query plans

Transaction Guidelines

  • Keep transactions short; avoid I/O inside transactions
  • Handle deadlocks with retry logic
  • Default isolation: Read Committed (usually sufficient)
  • Use Serializable only when phantom reads are unacceptable

Connection Pooling

SettingDevelopmentProduction
Min connections15
Max connections520-50
Idle timeout30s300s
Max lifetime1800s3600s

Pool size formula: (cores * 2) + disk_spindles. Always use pooling in production.

Naming Conventions

ElementConventionExample
Tablessnake_case, pluralusers, order_items
Columnssnake_casefirst_name, created_at
Primary Keyidid
Foreign Key{table}_iduser_id, order_id
Indexesix_{table}_{columns}ix_users_email

Example: Async SQLAlchemy schema patterns (illustrative)

Illustrative — this is one team's SQLAlchemy/Postgres setup shown as a concrete example. Substitute your ORM, driver, and schema conventions. The schema-design, indexing, and query-analysis guidance above is the engine-agnostic, reusable part.

Async SQLAlchemy Setup (<your-database-module>.py)

from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
    pass

engine = create_async_engine(
    DATABASE_URL,           # postgresql+asyncpg://...
    echo=False, future=True,
    pool_size=5, max_overflow=10,
    pool_recycle=3600,      # Recycle connections after 1 hour
    pool_pre_ping=True,     # Detect stale connections
)
async_session_maker = async_sessionmaker(
    engine, class_=AsyncSession, expire_on_commit=False
)

Session dependency (commit-on-success, rollback-on-error):

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session_maker() as session:
        try:
            yield session
            await session.commit()
        except Exception:
            await session.rollback()
            raise

Model Conventions

All models inherit from the shared declarative Base and follow these patterns:

ConventionPatternExample
Primary keyString(36), UUID as stringid: Mapped[str] = mapped_column(String(36), primary_key=True)
TimestampsDateTime(timezone=True) + utc_nowcreated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
Foreign keysExplicit ondelete policyForeignKey("projects.id", ondelete="CASCADE")
Nullable FKondelete="SET NULL"ForeignKey("users.id", ondelete="SET NULL")
IndexesOn FKs and query columnsindex=True on project_id, created_at, github_id
Type hintsMapped[] with mapped_columnSQLAlchemy 2.0 declarative style
RelationshipsTYPE_CHECKING guard for importsAvoids circular imports between modules

Models Overview

TableModelKey Fields
projectsProjectid, path (unique), name, created_at
task_refsTaskRefid, project_id (FK), conversation_id, session_id, created_by (FK)
usersUserid (uuid4), github_id (unique), github_login, avatar_url
user_projectsUserProjectuser_id (FK), project_id (FK), role, UniqueConstraint

Relationship Patterns

# Parent side - cascade delete orphans
tasks: Mapped[list["TaskRef"]] = relationship(
    "TaskRef", back_populates="project", cascade="all, delete-orphan"
)
# Child side
project: Mapped["Project"] = relationship("Project", back_populates="tasks")

Alembic Migration Conventions

  • Sync driver: Alembic uses psycopg2 (strips +asyncpg from URL)
  • Advisory locks: pg_advisory_lock(1573678) prevents concurrent migrations
  • Schema validation: main.py validates ORM vs DB schema on startup, logs warnings
  • Migration file naming: {hash}_{description}.py with upgrade() and downgrade()
  • All models imported in env.py: Required for autogenerate support
  • Safe pattern: Always include both upgrade() and downgrade() functions

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.