Przejdź do głównej zawartości

Operacje bazodanowe z CLI

Patrzysz na zapytanie, które trwa osiem sekund. Wyjście EXPLAIN to ściana sekwencyjnych skanów i zagnieżdżonych pętli. Twój product manager chce raportu łączącego pięć tabel z trzema poziomami agregacji. Stażyście właśnie pushnęli migrację, która usunęła kolumnę na produkcji. Praca z bazami danych to obszar, gdzie małe błędy są kosztowne, a ekspertyza trudna do zdobycia.

Claude Code przynosi tę ekspertyzę do twojego terminala. Czyta twój schemat, rozumie wzorce zapytań i generuje migracje bezpieczne do uruchomienia na produkcji. Pisze złożony SQL, nad którym spędziłbyś godzinę na debugowaniu, i wychwytuje błędy w migracjach, zanim trafią na staging. Ta lekcja obejmuje workflow bazodanowe, które sprawdzają się w rzeczywistych projektach.

  • Workflow do projektowania schematów i generowania bezpiecznych migracji z terminala
  • Prompty do pisania i optymalizacji złożonych zapytań
  • Wzorzec bezpieczeństwa migracji zapobiegający katastrofom produkcyjnym
  • Wzorce trybu headless do zautomatyzowanych audytów bazy danych

Rozpoczynając nową funkcjonalność wymagającą zmian w bazie danych, poproś Claude o zaprojektowanie schematu przed pisaniem jakiegokolwiek kodu.

Przejrzyj projekt schematu dokładnie. Typy kolumn, ograniczenia i indeksy są o wiele trudniejsze do zmiany po uruchomieniu migracji. Sprawdź konkretnie:

  • Czy klucze obce mają ustawione właściwe zachowanie ON DELETE?
  • Czy ograniczenia unikalności są tam, gdzie powinny być?
  • Czy indeksy są wystarczające dla zapytań, które planujesz uruchamiać?
  • Czy Claude użył tych samych konwencji co twój istniejący schemat?

Migracje to najniebezpieczniejsza operacja bazodanowa w systemie produkcyjnym. Zła migracja może zablokować tabele, usunąć dane lub spowodować przestój. Claude potrafi generować migracje unikające tych pułapek.

  1. Wygeneruj migrację

    Based on the schema changes we just designed, generate a
    migration file. Follow our existing migration patterns in
    migrations/ (or prisma/migrations/, or drizzle/).
    The migration must:
    - Use IF NOT EXISTS for all CREATE statements
    - Add columns as nullable first, then backfill, then add NOT NULL
    - Include an explicit DOWN migration for rollback
    - Never lock large tables (use concurrent index creation)
    - Include comments explaining each step
  2. Przejrzyj migrację przed uruchomieniem

    Show me the generated migration SQL. For each statement,
    explain: will it lock the table? How long will it take
    on a table with 5 million rows? Is it reversible?
  3. Przetestuj migrację na kopii

    Run the migration against our test database. Then verify:
    - All new tables/columns exist
    - Existing data is preserved
    - The application still connects and queries work
    - The rollback migration works (run down, then up again)
  4. Wdrażaj z pewnością

    Gdy migracja przejdzie review i testy, możesz wdrożyć ją z pewnością, że jest bezpieczna.

W przypadku zmian w istniejących tabelach z ruchem produkcyjnym, użyj wzorca expand-contract:

I need to rename the column "fname" to "first_name" on the users
table. This table has 2 million rows and serves 500 requests/second.
Generate a migration sequence that avoids downtime:
Phase 1 (expand): Add the new column "first_name" alongside "fname"
Phase 2 (dual-write): Application writes to both columns
Phase 3 (backfill): Copy data from "fname" to "first_name" in batches
Phase 4 (switch reads): Application reads from "first_name"
Phase 5 (contract): Drop the "fname" column
Generate the SQL migration for each phase. The backfill must
process in batches of 10,000 rows with a brief pause between
batches to avoid overwhelming the database.

Claude świetnie radzi sobie z SQL. Rozumie joiny, funkcje okna, CTE i implikacje wydajnościowe każdego podejścia.

Gdy zapytanie jest wolne, przekaż zapytanie i jego wyjście EXPLAIN do Claude:

This query takes 8 seconds. Here's the EXPLAIN ANALYZE output:
[paste output]
The query:
[paste query]
Read our schema to understand the table structure and existing
indexes. Tell me:
1. Why is it slow? (identify the specific bottleneck)
2. What indexes would help?
3. Can the query be restructured for better performance?
4. Show me the optimized version and its expected EXPLAIN plan.

W projektach korzystających z Prisma, Drizzle lub SQLAlchemy, poproś Claude o pisanie zapytań ORM zamiast surowego SQL:

Read our Drizzle schema in src/db/schema.ts. Write a query
using the Drizzle query builder that:
1. Finds all orders from the last 30 days
2. Includes the customer name and email
3. Includes the order items with product names
4. Filters by status "completed" or "shipped"
5. Sorts by order total descending
6. Paginates with cursor-based pagination
Use the Drizzle relational query API where possible.
Show me the generated SQL to verify it's efficient.

Dobre testy potrzebują realistycznych danych. Claude potrafi generować skrypty seedujące tworzące kompleksowe zestawy danych testowych.

Read our database schema and generate a seed script that creates:
- 50 users with realistic names and emails
- 10 teams with 3-15 members each
- 200 products across 5 categories
- 500 orders with realistic distribution (most recent month
has more orders, weekends have fewer)
- Reviews for ~60% of products with realistic rating distribution
(most are 4-5 stars, few are 1-2)
Use our existing seed utility in scripts/seed.ts as a reference.
The seed should be idempotent -- running it twice should not
create duplicates.

Konkretnie dla fixture’ów testowych:

Generate factory functions for our test suite following the
patterns in tests/fixtures/.
Create:
- createTestUser(overrides?) - creates a user with sensible defaults
- createTestTeam(owner, overrides?) - creates a team with the owner
- createTestOrder(user, products, overrides?) - creates an order
Each factory should return the created object and clean up
after the test (or use transactions that roll back).

Użyj trybu headless do zautomatyzowanych sprawdzeń kondycji bazy danych:

Okno terminala
# Check for common schema issues
claude -p "Read our database schema and check for:
1. Tables missing primary keys
2. Foreign keys without indexes
3. Columns that should be NOT NULL but aren't
4. Missing created_at/updated_at timestamps
5. Inconsistent naming conventions
6. Tables without any indexes beyond the primary key
Report each issue with the table name, column name,
and suggested fix." --output-format json > db-audit.json
Okno terminala
# Analyze query performance
claude -p "Read the slow query log at /var/log/postgresql/slow.log
and analyze the top 10 slowest queries. For each one:
1. Explain why it's slow
2. Suggest an index that would help
3. Show the optimized query if it can be restructured
4. Estimate the improvement
Read our schema to understand the table structure." \
--output-format json > query-audit.json
We use PostgreSQL. Generate queries that use PG-specific features:
1. Use JSONB columns for flexible metadata with GIN indexes
2. Use array columns for tags with array operators
3. Use full-text search with ts_vector and ts_query
4. Use row-level security for multi-tenant isolation
5. Use LISTEN/NOTIFY for real-time updates
Show me how to set up each feature and integrate it with
our ORM (Drizzle/Prisma).
Our production database is Cloudflare D1 (SQLite). Generate
migrations that work within SQLite's constraints:
- No ALTER TABLE for column renames or type changes
- No concurrent index creation
- Limited ALTER TABLE support (add column only)
For schema changes that SQLite can't handle directly, generate
the migration as: create new table, copy data, drop old table,
rename new table. Include proper transaction handling.

Gdy musisz zrozumieć, jak baza danych jest używana, zanim wprowadzisz zmiany:

Use sub-agents to investigate our database usage:
1. Find all queries in the codebase that touch the users table.
Group them by: SELECT, INSERT, UPDATE, DELETE. List the
file and line number for each.
2. Find all places where we use raw SQL instead of the ORM.
Check if any of them are vulnerable to SQL injection.
3. Analyze the migration history and list any migrations
that were destructive (dropped columns, tables, or data).
Check if they had proper rollback procedures.
Report findings so we can plan the schema changes safely.

Wygenerowana migracja blokuje tabele na produkcji. Claude nie uwzględnił rozmiaru tabeli. Zawsze pytaj: “This table has N million rows. Will this migration lock it? How long will it take?” W przypadku dużych tabel użyj narzędzi do zmian schematu online lub wzorca expand-contract.

Zapytania ORM są poprawne, ale wolne. ORM generuje nieoptymalny SQL. Poproś Claude o pokazanie wygenerowanego SQL: “Show me the raw SQL this Prisma/Drizzle query generates. Then compare its EXPLAIN plan with a hand-written query that does the same thing.”

Dane seedowe powodują naruszenia ograniczeń. Skrypt seedujący tworzy dane w złej kolejności (zamówienia przed użytkownikami, na przykład). Powiedz Claude: “Generate the seed data in dependency order. Users first, then teams, then products, then orders. Use actual IDs from previously created records.”

Migracja wsteczna nie działa. Dzieje się tak, gdy migracja down była myślana na końcu. Zawsze testuj pełny cykl: “Run the migration up, verify data, run the migration down, verify the schema is exactly as it was before. Show me the schema diff.”

Projekt schematu nie uwzględnia przyszłych zapytań. Claude zaprojektował schemat na podstawie bieżących wymagań, ale wiesz, że nadchodzi funkcjonalność wymagająca innych wzorców dostępu. Powiedz Claude: “We’ll also need to query this data by [describe the future query]. Does the current schema support that efficiently, or do we need additional indexes or denormalization?”

Twoja warstwa bazodanowa jest zaprojektowana, zmigrowana i zoptymalizowana. Teraz zbuduj endpointy API, które na niej stoją.