Option
HeimHeim Skill Datenbankverwaltung sql-database-assistant

sql-database-assistant

alirezarezvani/claude-skills alirezarezvani/claude-skills

Übersetzen Sie natürliche Sprache in SQL-Abfragen, optimieren Sie die Datenbankleistung, generieren Sie Migrationen, untersuchen Sie Schemata und arbeiten Sie mit ORMs für PostgreSQL, MySQL, SQLite und SQL Server.

...Alle erweitern
1
Zeit aktualisiert 2. September 2026

SQL-Datenbank-Assistent – AUSGEZEICHNETE Fachkompetenz

Übersicht

Der operative Begleiter beim Datenbankdesign. Während sich der Datenbankdesigner auf die Schemaarchitektur konzentriert und der Datenbankschema-Designer die ERD-Modellierung übernimmt, deckt diese Kompetenz den Alltag ab: das Schreiben von Abfragen, die Leistungsoptimierung, das Erstellen von Migrationen und das Überbrücken der Lücke zwischen Anwendungscode und Datenbank-Engines.

Kernkompetenzen

  • Von natürlicher Sprache zu SQL – Anforderungen in korrekte, leistungsstarke Abfragen übersetzen
  • Schema-Erkundung – Analyse von Live-Datenbanken in PostgreSQL, MySQL, SQLite und SQL Server
  • Abfrageoptimierung – EXPLAIN-Analyse, Indexempfehlungen, N+1-Erkennung, Umschreibungsmuster
  • Erstellung von Migrationen – Up-/Down-Skripte, Strategien ohne Ausfallzeiten, Rollback-Pläne
  • ORM-Integration – Prisma, Drizzle, TypeORM, SQLAlchemy-Muster und Ausweichlösungen
  • Unterstützung mehrerer Datenbanken – dialektbewusstes SQL mit Kompatibilitätshinweisen

Tools

Skript Zweck
scripts/query_optimizer.py Statische Analyse von SQL-Abfragen auf Leistungsprobleme
scripts/migration_generator.py Generierung von Vorlagen für Migrationsdateien anhand von Änderungsbeschreibungen
scripts/schema_explorer.py Generierung von Schemadokumentation aus Introspektionsabfragen

Von natürlicher Sprache zu SQL

Übersetzungsmuster

Befolgen Sie bei der Umwandlung von Anforderungen in SQL folgende Reihenfolge:

  1. Entitäten identifizieren – Substantive Tabellen zuordnen
  2. Beziehungen identifizieren – Verben JOINs oder Unterabfragen zuordnen
  3. Filter identifizieren – Adjektive/Bedingungen den WHERE-Klauseln zuordnen
  4. Aggregationen identifizieren – „Gesamt“, „Durchschnitt“, „Anzahl“ einer GROUP BY-Klausel zuordnen
  5. Sortierreihenfolge identifizieren – „top“, „neueste“, „höchste“ den ORDER BY + LIMIT-Klauseln zuordnen

Gängige Abfragevorlagen

Top-N pro Gruppe (Fensterfunktion)

SELECT * FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
  FROM employees
) ranked WHERE rn <= 3;

Laufende Summen

SELECT date, amount,
  SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM transactions;

Lückenerkennung

SELECT curr.id, curr.seq_num, prev.seq_num AS prev_seq
FROM records curr
LEFT JOIN records prev ON prev.seq_num = curr.seq_num - 1
WHERE prev.id IS NULL AND curr.seq_num > 1;

UPSERT (PostgreSQL)

INSERT INTO settings (key, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = EXCLUDED.updated_at;

UPSERT (MySQL)

INSERT INTO settings (key_name, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = VALUES(updated_at);

Siehe references/query_patterns.md für JOINs, CTEs, Fensterfunktionen, JSON-Operationen und mehr.

Schema-Erkundung

Introspektionsabfragen

PostgreSQL – Tabellen und Spalten auflisten

SELECT tabellenname, spaltenname, datentyp, is_nullable, spaltendefault
FROM information_schema.columns
WHERE tabellenschema = 'public'
ORDER BY tabellenname, ordinalposition;

PostgreSQL – Fremdschlüssel

SELECT tc.table_name, kcu.column_name,
  ccu.table_name AS foreign_table, ccu.column_name AS foreign_column
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY';

MySQL – Tabellengrößen

SELECT table_name, table_rows,
  ROUND(data_length / 1024 / 1024, 2) AS data_mb,
  ROUND(index_length / 1024 / 1024, 2) AS index_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY data_length DESC;

SQLite – Schema-Dump

SELECT name, sql FROM sqlite_master WHERE type = 'table' ORDER BY name;

SQL Server – Spalten mit Typen

SELECT t.name AS table_name, c.name AS column_name,
  ty.name AS data_type, c.max_length, c.is_nullable
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
JOIN sys.types ty ON c.user_type_id = ty.user_type_id
ORDER BY t.name, c.column_id;

Dokumentation aus dem Schema generieren

Verwenden Sie „scripts/schema_explorer.py“, um eine Dokumentation im Markdown- oder JSON-Format zu erstellen:

python scripts/schema_explorer.py --dialect postgres --tables all --format md
python scripts/schema_explorer.py --dialect mysql --tables users,orders --format json --json

Abfrageoptimierung

Workflow für die EXPLAIN-Analyse

  1. Führen Sie `EXPLAIN ANALYZE ` (PostgreSQL) oder `EXPLAIN FORMAT=JSON ` (MySQL)aus
  2. Identifizieren Sie den kostspieligsten Knoten – Seq Scan bei großen Tabellen, Nested Loop mit hohen Zeilenschätzungen
  3. Auf fehlende Indizes prüfen – sequentielle Scans auf gefilterten Spalten
  4. Suchen Sie nach Schätzfehlern – Abweichungen zwischen geplanten und tatsächlichen Zeilen deuten auf veraltete Statistiken hin
  5. Bewerten Sie die JOIN-Reihenfolge – stellen Sie sicher, dass die kleinste Ergebnismenge den Join bestimmt

Checkliste für Indexempfehlungen

  • Spalten in WHERE-Klauseln mit hoher Selektivität
  • Spalten in JOIN-Bedingungen (Fremdschlüssel)
  • Spalten in ORDER BY in Kombination mit LIMIT
  • Zusammengesetzte Indizes, die mit mehrspaltigen WHERE-Prädikaten übereinstimmen (Spalte mit der höchsten Selektivität an erster Stelle)
  • Teilindizes für Abfragen mit konstanten Filtern (z. B. WHERE status = 'active')
  • Abdeckende Indizes, um Tabellenabfragen bei lesintensiven Abfragen zu vermeiden

Muster zur Abfrageumformulierung

Anti-Muster Umschreibung
SELECT * FROM bestellungen SELECT id, status, total FROM orders (explizite Spalten)
WHERE YEAR(created_at) = 2025 WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01' (SARG-fähig)
Korrelierte Unterabfrage in SELECT LEFT JOIN mit Aggregation
NOT IN (SELECT ...) mit NULL-Werten NOT EXISTS (SELECT 1 ...)
UNION (dedup), wenn nicht erforderlich UNION ALL
LIKE '%search%' Volltextsuchindex (GIN/FULLTEXT)
ORDER BY RAND() Anwendungsseitige Zufallsauswahl oder TABLESAMPLE

N+1-Erkennung

Symptome:

  • Anwendungsschleife, die pro übergeordneter Zeile eine Abfrage ausführt
  • ORM lädt verwandte Entitäten innerhalb einer Schleife verzögert („Lazy Loading“)
  • Das Abfrageprotokoll zeigt Hunderte identischer SELECT-Muster mit unterschiedlichen IDs an

Behebungen:

  • Verwenden Sie Eager Loading (include in Prisma, joinedload in SQLAlchemy)
  • Abfragen bündeln mit WHERE id IN (...)
  • Verwenden Sie das DataLoader-Muster für GraphQL-Resolver

Statisches Analyse-Tool

python scripts/query_optimizer.py --query "SELECT * FROM orders WHERE status = 'pending'" --dialect postgres
python scripts/query_optimizer.py --query queries.sql --dialect mysql --json

Siehe references/optimization_guide.md für Informationen zum Lesen von EXPLAIN-Plänen, zu Indextypen und zum Connection-Pooling.

Generierung von Migrationen

Migrationsmuster ohne Ausfallzeiten

Hinzufügen einer Spalte (sicher)

-- Up
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Down
ALTER TABLE users DROP COLUMN phone;

Umbenennen einer Spalte (Erweitern–Reduzieren)

-- Schritt 1: Neue Spalte hinzufügen
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);
-- Schritt 2: Nachträgliche Einpflegung
UPDATE users SET full_name = name;
-- Schritt 3: Bereitstellung der App, die beide Spalten liest
-- Schritt 4: Bereitstellung der App, die nur in die neue Spalte schreibt
-- Schritt 5: Löschen der alten Spalte
ALTER TABLE users DROP COLUMN name;

Hinzufügen einer NOT NULL-Spalte (sichere Abfolge)

-- Schritt 1: Hinzufügen einer Spalte, die NULL-Werte zulässt
ALTER TABLE orders ADD COLUMN region VARCHAR(50);
-- Schritt 2: Nachbelegen mit Standardwert
UPDATE orders SET region = 'unknown' WHERE region IS NULL;
-- Schritt 3: Einschränkung hinzufügen
ALTER TABLE orders ALTER COLUMN region SET NOT NULL;
ALTER TABLE orders ALTER COLUMN region SET DEFAULT 'unknown';

Indexerstellung (blockierungsfrei, PostgreSQL)

CREATE INDEX CONCURRENTLY idx_orders_status ON orders (status);

Strategien zum Nachfüllen von Daten

  • Batch-Aktualisierungen – Verarbeitung in Blöcken von 1.000–10.000 Zeilen, um Sperrkonflikte zu vermeiden
  • Hintergrundjobs – führen Nachvervollständigungen asynchron mit Fortschrittsverfolgung durch
  • Dual-Write – Schreiben in alte und neue Spalten während der Übergangsphase
  • Validierungsabfragen – Überprüfung der Zeilenanzahl und Datenintegrität nach jedem Batch

Rollback-Strategien

Jede Migration muss über ein reversibles Rollback-Skript verfügen. Bei irreversiblen Änderungen:

  1. Sicherung vor der Ausführungpg_dump der betroffenen Tabellen
  2. Feature-Flags – die Anwendung kann zwischen dem Lesen aus dem alten und dem neuen Schema wechseln
  3. Schattentabellen – während des Migrationsfensters eine Kopie der ursprünglichen Tabelle aufbewahren

Tool zur Migrationsgenerierung

python scripts/migration_generator.py --change "add email_verified boolean to users" --dialect postgres --format sql
python scripts/migration_generator.py --change „Umbenennung der Spalte ‚name‘ in ‚full_name‘ in der Tabelle ‚customers‘“ --dialect mysql --format alembic --json

Unterstützung mehrerer Datenbanken

Dialektunterschiede

Funktion PostgreSQL MySQL SQLite SQL Server
UPSERT BEI KONFLIKT AKTUALISIEREN Bei doppelten Schlüsseln aktualisieren BEI KONFLIKT AKTUALISIEREN MERGE
Boolesch Native BOOLEAN TINYINT(1) INTEGER BIT
Autoinkrement SERIAL / GENERATED AUTO_INCREMENT GANZZAHL PRIMÄR-SCHLÜSSEL IDENTITY
JSON JSONB (indiziert) JSON Text (ext) NVARCHAR(MAX)
Array Natives ARRAY Nicht unterstützt Nicht unterstützt Nicht unterstützt
CTE (rekursiv) Volle Unterstützung 8.0+ 3.8.3 Volle Unterstützung
Fensterfunktionen Volle Unterstützung 8.0+ 3.25.0+ Volle Unterstützung
Volltextsuche tsvector + GIN FULLTEXT -Index FTS5-Erweiterung Volltextkatalog
LIMIT/OFFSET LIMIT n OFFSET m LIMIT n OFFSET m LIMIT n OFFSET m OFFSET m, NACHHER NUR DIE NÄCHSTEN n ZEILEN ABFRAGEN

Tipps zur Kompatibilität

  • Verwenden Sie stets parametrisierte Abfragen – dies verhindert SQL-Injection in allen Dialekten
  • Vermeiden Sie dialektspezifische Funktionen in gemeinsam genutztem Code – verpacken Sie diese in eine Adapterschicht
  • Testen Sie Migrationen auf der Ziel-Engine„information_schema“ variiert je nach Engine
  • Verwenden Sie das ISO-Datumsformat „YYYY-MM-DD“ funktioniert überall
  • Identifikatoren in Anführungszeichen setzen – doppelte Anführungszeichen (SQL-Standard) oder Backticks (MySQL) verwenden

ORM-Muster

Prisma

Schema-Definition

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId Int
}

Migrationen: npx prisma migrate dev --name add_user_email Abfrage-API: prisma.user.findMany({ where: { email: { contains: '@' } }, include: { posts: true } }) Raw-SQL-Escape-Hatch: prisma.$queryRaw\SELECT * FROM users WHERE id = ${userId}``

Drizzle

Schema-First-Definition

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow(),
});

Abfragegenerator: db.select().from(users).where(eq(users.email, email)) Migrationen: npx drizzle-kit generate:pg, anschließend npx drizzle-kit push:pg

TypeORM

Entity-Dekoratoren

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @OneToMany(() => Post, post => post.author)
  posts: Post[];
}

Repository-Muster: userRepo.find({ where: { email }, relations: ['posts'] }) Migrationen: npx typeorm migration:generate -n AddUserEmail

SQLAlchemy

Deklarative Modelle

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False)
    name = Column(String(255))
    posts = relationship('Post', back_populates='author')

Sitzungsverwaltung: Verwenden Sie immer `with Session()` als `session: context manager` Alembic-Migrationen: ` alembic revision --autogenerate -m "add user email"`

Siehe references/orm_patterns.md für Gegenüberstellungen und Migrationsabläufe pro ORM.

Datenintegrität

Strategie für Einschränkungen

  • Primärschlüssel – jede Tabelle muss einen haben; Surrogatschlüssel (serial/UUID) sind zu bevorzugen
  • Fremdschlüssel – referenzielle Integrität durchsetzen; ON-DELETE-Verhalten explizit definieren
  • UNIQUE-Einschränkungen – für Eindeutigkeit auf Geschäftsebene (E-Mail, Slug, API-Schlüssel)
  • CHECK-Einschränkungen – Validierung von Bereichen, Aufzählungen und Geschäftsregeln auf Datenbankebene
  • NOT NULL – standardmäßig NOT NULL; nur dann auf „nullable“ setzen, wenn die Angabe wirklich optional ist

Transaktionsisolationsstufen

Stufe Dirty Read Nicht wiederholbarer Lesezugriff Phantom-Lesezugriff Anwendungsfall
UNVERBINDLICHES LESEN Ja Ja Ja Wird niemals empfohlen
READ COMMITTED Nein Ja Ja Standard für PostgreSQL, allgemeines OLTP
REPEATABLE READ Nein Nein Ja (InnoDB: Nein) Finanzberechnungen
SERIALISIERBAR Nein Nein Nein Kritische Konsistenz (Abrechnung, Lagerbestand)

Vermeidung von Deadlocks

  1. Konsistente Reihenfolge der Sperren – Sperren immer in derselben Tabellen-/Zeilenreihenfolge erwerben
  2. Kurze Transaktionen – Minimierung der Zeit zwischen erster Sperre und Commit
  3. Advisory-Sperren — Verwendung von pg_advisory_lock() zur Koordination auf Anwendungsebene
  4. Wiederholungslogik – Deadlock-Fehler abfangen und mit exponentiellem Backoff wiederholen

Sicherung und Wiederherstellung

PostgreSQL

# Vollständige Sicherung
pg_dump -Fc --no-owner dbname > backup.dump
# Wiederherstellung
pg_restore -d dbname --clean --no-owner backup.dump
# Wiederherstellung zu einem bestimmten Zeitpunkt: WAL-Archivierung + restore_command konfigurieren

MySQL

# Vollsicherung
mysqldump --single-transaction --routines --triggers dbname > backup.sql
# Wiederherstellung
mysql dbname < backup.sql
# Binärprotokoll für PITR: mysqlbinlog --start-datetime="2025-01-01 00:00:00" binlog.000001

SQLite

# Sicherung (sicher bei gleichzeitigen Lesezugriffen)
sqlite3 dbname ".backup backup.db"

Bewährte Verfahren für Backups

  • Automatisieren – Cron- oder systemd-Timer, niemals ausschließlich manuell
  • Wiederherstellungen testen — Ungetestete Sicherungen sind keine Sicherungen
  • Externe Kopien – S3, GCS oder separate Region
  • Aufbewahrungsrichtlinie – täglich für 7 Tage, wöchentlich für 4 Wochen, monatlich für 12 Monate
  • Überwachen Sie die Größe und Dauer der Backups – plötzliche Änderungen deuten auf Probleme hin

Anti-Muster

Anti-Muster Problem Lösung
SELECT * Überträgt unnötige Daten, führt bei Schemaänderungen zu Fehlern Explizite Spaltenliste
Fehlende Indizes auf FK-Spalten Langsame JOINs und kaskadierende Löschungen Indizes auf alle Fremdschlüssel hinzufügen
N+1-Abfragen 1 + N Roundtrips zur Datenbank Eager Loading oder Batch-Abfragen
Implizite Typumwandlung WHERE id = '123' verhindert die Verwendung von Indizes Typübereinstimmungen in Prädikaten
Kein Connection-Pooling Schöpft die Verbindungen unter Last aus PgBouncer, ProxySQL oder ORM-Pool
Unbegrenzte Abfragen Ohne LIMIT besteht die Gefahr, dass Millionen von Zeilen zurückgegeben werden Immer paginieren
Speichern von Geldbeträgen als FLOAT Rundungsfehler Verwenden Sie DECIMAL(19,4) oder Cent-Beträge als Ganzzahlen
„God-Tabellen“ Eine Tabelle mit mehr als 50 Spalten Normalisieren oder vertikale Partitionierung verwenden
Überall „Soft Deletes“ Verkompliziert jede Abfrage mit WHERE deleted_at IS NULL Tabellen archivieren oder Event Sourcing
Verkettung von Rohzeichenfolgen SQL-Injection Stets parametrisierte Abfragen

Querverweise

Fähigkeit Beziehung
Datenbankdesigner Schema-Architektur, Normalisierungsanalyse, ERD-Erstellung
Datenbank-Schema-Designer Visuelle ERD-Modellierung, Beziehungsabbildung
Migrationsarchitekt Koordination komplexer, mehrstufiger Migrationen
API-Design-Prüfer Sicherstellung, dass API-Endpunkte mit Abfragemustern übereinstimmen
Observability-Plattform Überwachung der Abfrageleistung, Warnmeldungen bei langsamen Abfragen
Auf GitHub ansehen
---
name: sql-database-assistant
description: Translate natural language into SQL queries, optimize database performance, generate migrations, explore schemas, and work with ORMs across PostgreSQL, MySQL, SQLite, and SQL Server.
---

# SQL Database Assistant - POWERFUL Tier Skill

## Overview

The operational companion to database design. While **database-designer** focuses on schema architecture and **database-schema-designer** handles ERD modeling, this skill covers the day-to-day: writing queries, optimizing performance, generating migrations, and bridging the gap between application code and database engines.

### Core Capabilities

- **Natural Language to SQL** — translate requirements into correct, performant queries
- **Schema Exploration** — introspect live databases across PostgreSQL, MySQL, SQLite, SQL Server
- **Query Optimization** — EXPLAIN analysis, index recommendations, N+1 detection, rewrite patterns
- **Migration Generation** — up/down scripts, zero-downtime strategies, rollback plans
- **ORM Integration** — Prisma, Drizzle, TypeORM, SQLAlchemy patterns and escape hatches
- **Multi-Database Support** — dialect-aware SQL with compatibility guidance

### Tools

| Script | Purpose |
|--------|---------|
| `scripts/query_optimizer.py` | Static analysis of SQL queries for performance issues |
| `scripts/migration_generator.py` | Generate migration file templates from change descriptions |
| `scripts/schema_explorer.py` | Generate schema documentation from introspection queries |

---

## Natural Language to SQL

### Translation Patterns

When converting requirements to SQL, follow this sequence:

1. **Identify entities** — map nouns to tables
2. **Identify relationships** — map verbs to JOINs or subqueries
3. **Identify filters** — map adjectives/conditions to WHERE clauses
4. **Identify aggregations** — map "total", "average", "count" to GROUP BY
5. **Identify ordering** — map "top", "latest", "highest" to ORDER BY + LIMIT

### Common Query Templates

**Top-N per group (window function)**
```sql
SELECT * FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
  FROM employees
) ranked WHERE rn <= 3;
```

**Running totals**
```sql
SELECT date, amount,
  SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM transactions;
```

**Gap detection**
```sql
SELECT curr.id, curr.seq_num, prev.seq_num AS prev_seq
FROM records curr
LEFT JOIN records prev ON prev.seq_num = curr.seq_num - 1
WHERE prev.id IS NULL AND curr.seq_num > 1;
```

**UPSERT (PostgreSQL)**
```sql
INSERT INTO settings (key, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = EXCLUDED.updated_at;
```

**UPSERT (MySQL)**
```sql
INSERT INTO settings (key_name, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = VALUES(updated_at);
```

> See references/query_patterns.md for JOINs, CTEs, window functions, JSON operations, and more.

---

## Schema Exploration

### Introspection Queries

**PostgreSQL — list tables and columns**
```sql
SELECT table_name, column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position;
```

**PostgreSQL — foreign keys**
```sql
SELECT tc.table_name, kcu.column_name,
  ccu.table_name AS foreign_table, ccu.column_name AS foreign_column
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY';
```

**MySQL — table sizes**
```sql
SELECT table_name, table_rows,
  ROUND(data_length / 1024 / 1024, 2) AS data_mb,
  ROUND(index_length / 1024 / 1024, 2) AS index_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY data_length DESC;
```

**SQLite — schema dump**
```sql
SELECT name, sql FROM sqlite_master WHERE type = 'table' ORDER BY name;
```

**SQL Server — columns with types**
```sql
SELECT t.name AS table_name, c.name AS column_name,
  ty.name AS data_type, c.max_length, c.is_nullable
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
JOIN sys.types ty ON c.user_type_id = ty.user_type_id
ORDER BY t.name, c.column_id;
```

### Generating Documentation from Schema

Use `scripts/schema_explorer.py` to produce markdown or JSON documentation:

```bash
python scripts/schema_explorer.py --dialect postgres --tables all --format md
python scripts/schema_explorer.py --dialect mysql --tables users,orders --format json --json
```

---

## Query Optimization

### EXPLAIN Analysis Workflow

1. **Run EXPLAIN ANALYZE** (PostgreSQL) or **EXPLAIN FORMAT=JSON** (MySQL)
2. **Identify the costliest node** — Seq Scan on large tables, Nested Loop with high row estimates
3. **Check for missing indexes** — sequential scans on filtered columns
4. **Look for estimation errors** — planned vs actual rows divergence signals stale statistics
5. **Evaluate JOIN order** — ensure the smallest result set drives the join

### Index Recommendation Checklist

- Columns in WHERE clauses with high selectivity
- Columns in JOIN conditions (foreign keys)
- Columns in ORDER BY when combined with LIMIT
- Composite indexes matching multi-column WHERE predicates (most selective column first)
- Partial indexes for queries with constant filters (e.g., `WHERE status = 'active'`)
- Covering indexes to avoid table lookups for read-heavy queries

### Query Rewriting Patterns

| Anti-Pattern | Rewrite |
|-------------|---------|
| `SELECT * FROM orders` | `SELECT id, status, total FROM orders` (explicit columns) |
| `WHERE YEAR(created_at) = 2025` | `WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01'` (sargable) |
| Correlated subquery in SELECT | LEFT JOIN with aggregation |
| `NOT IN (SELECT ...)` with NULLs | `NOT EXISTS (SELECT 1 ...)` |
| `UNION` (dedup) when not needed | `UNION ALL` |
| `LIKE '%search%'` | Full-text search index (GIN/FULLTEXT) |
| `ORDER BY RAND()` | Application-side random sampling or `TABLESAMPLE` |

### N+1 Detection

**Symptoms:**
- Application loop that executes one query per parent row
- ORM lazy-loading related entities inside a loop
- Query log shows hundreds of identical SELECT patterns with different IDs

**Fixes:**
- Use eager loading (`include` in Prisma, `joinedload` in SQLAlchemy)
- Batch queries with `WHERE id IN (...)`
- Use DataLoader pattern for GraphQL resolvers

### Static Analysis Tool

```bash
python scripts/query_optimizer.py --query "SELECT * FROM orders WHERE status = 'pending'" --dialect postgres
python scripts/query_optimizer.py --query queries.sql --dialect mysql --json
```

> See references/optimization_guide.md for EXPLAIN plan reading, index types, and connection pooling.

---

## Migration Generation

### Zero-Downtime Migration Patterns

**Adding a column (safe)**
```sql
-- Up
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Down
ALTER TABLE users DROP COLUMN phone;
```

**Renaming a column (expand-contract)**
```sql
-- Step 1: Add new column
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);
-- Step 2: Backfill
UPDATE users SET full_name = name;
-- Step 3: Deploy app reading both columns
-- Step 4: Deploy app writing only new column
-- Step 5: Drop old column
ALTER TABLE users DROP COLUMN name;
```

**Adding a NOT NULL column (safe sequence)**
```sql
-- Step 1: Add nullable
ALTER TABLE orders ADD COLUMN region VARCHAR(50);
-- Step 2: Backfill with default
UPDATE orders SET region = 'unknown' WHERE region IS NULL;
-- Step 3: Add constraint
ALTER TABLE orders ALTER COLUMN region SET NOT NULL;
ALTER TABLE orders ALTER COLUMN region SET DEFAULT 'unknown';
```

**Index creation (non-blocking, PostgreSQL)**
```sql
CREATE INDEX CONCURRENTLY idx_orders_status ON orders (status);
```

### Data Backfill Strategies

- **Batch updates** — process in chunks of 1000-10000 rows to avoid lock contention
- **Background jobs** — run backfills asynchronously with progress tracking
- **Dual-write** — write to old and new columns during transition period
- **Validation queries** — verify row counts and data integrity after each batch

### Rollback Strategies

Every migration must have a reversible down script. For irreversible changes:

1. **Backup before execution** — `pg_dump` the affected tables
2. **Feature flags** — application can switch between old/new schema reads
3. **Shadow tables** — keep a copy of the original table during migration window

### Migration Generator Tool

```bash
python scripts/migration_generator.py --change "add email_verified boolean to users" --dialect postgres --format sql
python scripts/migration_generator.py --change "rename column name to full_name in customers" --dialect mysql --format alembic --json
```

---

## Multi-Database Support

### Dialect Differences

| Feature | PostgreSQL | MySQL | SQLite | SQL Server |
|---------|-----------|-------|--------|------------|
| UPSERT | `ON CONFLICT DO UPDATE` | `ON DUPLICATE KEY UPDATE` | `ON CONFLICT DO UPDATE` | `MERGE` |
| Boolean | Native `BOOLEAN` | `TINYINT(1)` | `INTEGER` | `BIT` |
| Auto-increment | `SERIAL` / `GENERATED` | `AUTO_INCREMENT` | `INTEGER PRIMARY KEY` | `IDENTITY` |
| JSON | `JSONB` (indexed) | `JSON` | Text (ext) | `NVARCHAR(MAX)` |
| Array | Native `ARRAY` | Not supported | Not supported | Not supported |
| CTE (recursive) | Full support | 8.0+ | 3.8.3+ | Full support |
| Window functions | Full support | 8.0+ | 3.25.0+ | Full support |
| Full-text search | `tsvector` + GIN | `FULLTEXT` index | FTS5 extension | Full-text catalog |
| LIMIT/OFFSET | `LIMIT n OFFSET m` | `LIMIT n OFFSET m` | `LIMIT n OFFSET m` | `OFFSET m ROWS FETCH NEXT n ROWS ONLY` |

### Compatibility Tips

- **Always use parameterized queries** — prevents SQL injection across all dialects
- **Avoid dialect-specific functions in shared code** — wrap in adapter layer
- **Test migrations on target engine** — `information_schema` varies between engines
- **Use ISO date format** — `'YYYY-MM-DD'` works everywhere
- **Quote identifiers** — use double quotes (SQL standard) or backticks (MySQL)

---

## ORM Patterns

### Prisma

**Schema definition**
```prisma
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId Int
}
```

**Migrations**: `npx prisma migrate dev --name add_user_email`
**Query API**: `prisma.user.findMany({ where: { email: { contains: '@' } }, include: { posts: true } })`
**Raw SQL escape hatch**: `prisma.$queryRaw\`SELECT * FROM users WHERE id = ${userId}\``

### Drizzle

**Schema-first definition**
```typescript
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow(),
});
```

**Query builder**: `db.select().from(users).where(eq(users.email, email))`
**Migrations**: `npx drizzle-kit generate:pg` then `npx drizzle-kit push:pg`

### TypeORM

**Entity decorators**
```typescript
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @OneToMany(() => Post, post => post.author)
  posts: Post[];
}
```

**Repository pattern**: `userRepo.find({ where: { email }, relations: ['posts'] })`
**Migrations**: `npx typeorm migration:generate -n AddUserEmail`

### SQLAlchemy

**Declarative models**
```python
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False)
    name = Column(String(255))
    posts = relationship('Post', back_populates='author')
```

**Session management**: Always use `with Session() as session:` context manager
**Alembic migrations**: `alembic revision --autogenerate -m "add user email"`

> See references/orm_patterns.md for side-by-side comparisons and migration workflows per ORM.

---

## Data Integrity

### Constraint Strategy

- **Primary keys** — every table must have one; prefer surrogate keys (serial/UUID)
- **Foreign keys** — enforce referential integrity; define ON DELETE behavior explicitly
- **UNIQUE constraints** — for business-level uniqueness (email, slug, API key)
- **CHECK constraints** — validate ranges, enums, and business rules at the DB level
- **NOT NULL** — default to NOT NULL; make nullable only when genuinely optional

### Transaction Isolation Levels

| Level | Dirty Read | Non-Repeatable Read | Phantom Read | Use Case |
|-------|-----------|-------------------|-------------|----------|
| READ UNCOMMITTED | Yes | Yes | Yes | Never recommended |
| READ COMMITTED | No | Yes | Yes | Default for PostgreSQL, general OLTP |
| REPEATABLE READ | No | No | Yes (InnoDB: No) | Financial calculations |
| SERIALIZABLE | No | No | No | Critical consistency (billing, inventory) |

### Deadlock Prevention

1. **Consistent lock ordering** — always acquire locks in the same table/row order
2. **Short transactions** — minimize time between first lock and commit
3. **Advisory locks** — use `pg_advisory_lock()` for application-level coordination
4. **Retry logic** — catch deadlock errors and retry with exponential backoff

---

## Backup & Restore

### PostgreSQL
```bash
# Full backup
pg_dump -Fc --no-owner dbname > backup.dump
# Restore
pg_restore -d dbname --clean --no-owner backup.dump
# Point-in-time recovery: configure WAL archiving + restore_command
```

### MySQL
```bash
# Full backup
mysqldump --single-transaction --routines --triggers dbname > backup.sql
# Restore
mysql dbname < backup.sql
# Binary log for PITR: mysqlbinlog --start-datetime="2025-01-01 00:00:00" binlog.000001
```

### SQLite
```bash
# Backup (safe with concurrent reads)
sqlite3 dbname ".backup backup.db"
```

### Backup Best Practices
- **Automate** — cron or systemd timer, never manual-only
- **Test restores** — untested backups are not backups
- **Offsite copies** — S3, GCS, or separate region
- **Retention policy** — daily for 7 days, weekly for 4 weeks, monthly for 12 months
- **Monitor backup size and duration** — sudden changes signal issues

---

## Anti-Patterns

| Anti-Pattern | Problem | Fix |
|-------------|---------|-----|
| `SELECT *` | Transfers unnecessary data, breaks on schema changes | Explicit column list |
| Missing indexes on FK columns | Slow JOINs and cascading deletes | Add indexes on all foreign keys |
| N+1 queries | 1 + N round trips to database | Eager loading or batch queries |
| Implicit type coercion | `WHERE id = '123'` prevents index use | Match types in predicates |
| No connection pooling | Exhausts connections under load | PgBouncer, ProxySQL, or ORM pool |
| Unbounded queries | No LIMIT risks returning millions of rows | Always paginate |
| Storing money as FLOAT | Rounding errors | Use `DECIMAL(19,4)` or integer cents |
| God tables | One table with 50+ columns | Normalize or use vertical partitioning |
| Soft deletes everywhere | Complicates every query with `WHERE deleted_at IS NULL` | Archive tables or event sourcing |
| Raw string concatenation | SQL injection | Parameterized queries always |

---

## Cross-References

| Skill | Relationship |
|-------|-------------|
| **database-designer** | Schema architecture, normalization analysis, ERD generation |
| **database-schema-designer** | Visual ERD modeling, relationship mapping |
| **migration-architect** | Complex multi-step migration orchestration |
| **api-design-reviewer** | Ensuring API endpoints align with query patterns |
| **observability-platform** | Query performance monitoring, slow query alerts |

Alle Dateien

0 Dateien

sql-database-assistant installieren

Laden Sie die Skill-Dateien herunter und entpacken Sie sie in Ihr Verzeichnis „.claude/skills/“.

ZIP herunterladen

Klonen Sie das Repository und kopieren Sie die Skill-Dateien in Ihr Projekt.

git clone https://github.com/alirezarezvani/claude-skills/tree/main/engineering/skills/sql-database-assistant # Copy SKILL.md to your .claude/skills/ directory

Kopieren Kopieren
Schnelle Einrichtung: Kopiere den Skill-Ordner nach .claude/skills/. Claude erkennt den Skill automatisch und nutzt ihn.

Ähnliche Skills

microservices-patterns
Zeit aktualisiert 29. Juni 2026
jpa-patterns
Zeit aktualisiert 30. Juni 2026
fabric-lakehouse
Zeit aktualisiert 30. Juni 2026
prisma-expert
Zeit aktualisiert 29. Juni 2026
OR