Claude Code Performance: Code optimieren und Bottlenecks finden mit KI

Performance-Probleme sind heimtückisch: Sie erscheinen selten dort, wo man sucht. Eine Seite lädt langsam — aber liegt es am Datenbankquery, am JavaScript-Bundle, am fehlenden Index, oder am N+1-Problem im ORM? Die Antwort auf diese Frage kann Stunden dauern, wenn man sie manuell durchsucht. Mit Claude Code Performance-Analyse verkürzt sich dieser Prozess drastisch, weil das Tool den gesamten Kontext auf einmal sieht: Code, Datenbankschema, Build-Konfiguration, Profiling-Ergebnisse.

Dieser Artikel zeigt konkret, wie Claude Code bei den sechs häufigsten Performance-Themen hilft: Profiling und Bottleneck-Analyse, Algorithmus-Optimierung, Datenbankabfragen, Caching-Strategien, Frontend-Performance und asynchrone Verarbeitung. Kein theoretisches Konzept — konkrete Prompts und reale Ergebnisse.

Claude Code Mastery — Performance, Agents, Hooks auf Deutsch

Der Kurs zeigt, wie du Claude Code wirklich produktiv einsetzt — für Performance-Arbeit, autonome Agents und professionelle Workflows. Einmalig bezahlt, kein Abo.

Zum Kurs — ab €29 → Basis ab €29 · Pro ab €49 · Kein Abo · 14 Tage Rückgaberecht

1. Profiling und Bottleneck-Analyse

Performance-Optimierung ohne Profiling ist Raten. Bevor man irgendetwas ändert, muss man wissen, wo die Zeit tatsächlich verloren geht — nicht wo man es vermutet. Claude Code hilft dabei auf zwei Ebenen: beim Einrichten des richtigen Profiling-Tools und beim Interpretieren der Ergebnisse.

Python: py-spy und cProfile

Für Python-Anwendungen sind py-spy und cProfile die wichtigsten Profiling-Tools. py-spy läuft ohne Code-Änderung direkt gegen einen laufenden Prozess:

py-spy record -o profile.svg --pid $(pgrep -f myapp.py) --duration 30

Das erzeugte Flamegraph-SVG zeigt sofort, welche Funktionen die meiste Zeit verbrauchen. Übergib es an Claude Code:

claude "Analysiere diesen py-spy Output und erkläre die drei größten Bottlenecks:
$(cat profile.txt)"

Claude Code liest die Profiling-Daten, identifiziert die Hot Paths und erklärt, warum diese Pfade so viel Zeit verbrauchen — meist weil sie O(n²)-Operationen in Schleifen ausführen oder Datenbankzugriffe wiederholen, die einmal reichen würden.

JVM: async-profiler

Für Java- und Kotlin-Anwendungen liefert async-profiler CPU- und Speicher-Flamegraphs ohne Overhead:

./asprof -e cpu -d 30 -f profile.html $(jps | grep MyApp | cut -d' ' -f1)
claude "Ich habe einen async-profiler HTML-Report. Welche Methoden verbrauchen
am meisten CPU und was sind mögliche Ursachen?" < profile_summary.txt

Browser: Chrome DevTools Performance Tab

Im Browser ist der Performance Tab in Chrome DevTools das Standardwerkzeug. Aufzeichnung exportieren, als JSON oder Screenshot übergeben:

claude "Dieses Performance-Trace zeigt eine lange Task-Blockade im Main Thread.
Was ist die Ursache und wie kann ich die Arbeit aufteilen?
[Performance-Trace-Daten einfügen]"

Reihenfolge bei Performance-Problemen: Erst messen, dann optimieren. Claude Code kann nicht raten, ob ein Problem im Backend, Frontend, der Datenbank oder im Netzwerk liegt — aber es kann Profiling-Daten sehr schnell interpretieren und die Ursache benennen. Das Profiling-Setup ist deshalb der erste Schritt, nicht der letzte.

2. Algorithmus-Optimierung und Komplexität

Viele Performance-Probleme entstehen nicht durch schlechte Infrastruktur, sondern durch ineffiziente Algorithmen. Eine O(n²)-Operation, die bei 100 Elementen kaum auffällt, wird bei 10.000 Elementen zum Showstopper. Claude Code erkennt diese Muster zuverlässig — auch dann, wenn der Code auf den ersten Blick harmlos aussieht.

claude "Analysiere diese Funktion auf Zeitkomplexität und schlage
eine effizientere Implementierung vor:

def find_duplicates(items):
    duplicates = []
    for i in range(len(items)):
        for j in range(i + 1, len(items)):
            if items[i] == items[j] and items[i] not in duplicates:
                duplicates.append(items[i])
    return duplicates"

Claude Code erkennt hier sofort drei Probleme: die verschachtelte Schleife (O(n²)), das in-Check auf einer Liste (ebenfalls O(n) statt O(1) bei einem Set), und den redundanten Duplikat-Check. Die Antwort liefert die optimierte Version:

# O(n) statt O(n³) — drei Ebenen Verbesserung
def find_duplicates(items):
    seen = set()
    duplicates = set()
    for item in items:
        if item in seen:
            duplicates.add(item)
        seen.add(item)
    return list(duplicates)

Besonders wertvoll ist Claude Code bei Algorithmen, die über mehrere Funktionen und Dateien verteilt sind. Ein O(n)-Lookup der mitten in einer Schleife steckt, die selbst in einer anderen Funktion aufgerufen wird — das ist schwer zu sehen, wenn man nur einzelne Dateien liest. Claude Code liest die gesamte Aufrufkette und findet das Problem an der Wurzel.

Datenstrukturen gezielt wählen

Ein häufiger Fall: Eine Liste wird verwendet, wo ein Dictionary oder Set die bessere Wahl wäre. Übergib einfach die relevanten Dateien:

claude "Schau dir diese Datei an und identifiziere alle Stellen, wo
Listen für Lookup-Operationen verwendet werden, obwohl ein Set oder
Dict effizienter wäre. Zeige konkrete Umstellungen."
"In Zeile 47 verwendest du if user_id in active_users_list in einer Schleife. Da active_users_list 50.000 Einträge haben kann, ist das O(n) pro Iteration — insgesamt O(n²). Konvertiere active_users_list einmalig vor der Schleife in ein Set, dann ist jeder Lookup O(1)."

3. Datenbankabfragen optimieren

Datenbankprobleme sind die häufigste Ursache für langsame Webanwendungen. Drei Muster stehen dabei ganz oben: fehlende Indizes, nicht analysierte Queries, und das N+1-Problem in ORMs. Claude Code kennt alle drei und findet sie auch dann, wenn sie gut versteckt sind.

Fehlende Indizes erkennen

Übergib Schema und die langsamen Queries:

claude "Diese Query läuft auf einer Tabelle mit 2 Millionen Rows und braucht 8 Sekunden.
Welche Indizes fehlen?

Schema:
CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  user_id BIGINT NOT NULL,
  status VARCHAR(20) NOT NULL,
  created_at TIMESTAMP NOT NULL,
  total_amount DECIMAL(10,2)
);

Query:
SELECT * FROM orders
WHERE user_id = 12345
  AND status = 'pending'
ORDER BY created_at DESC
LIMIT 20;"

Claude Code analysiert den Ausführungsplan gedanklich, erkennt dass user_id und status zusammen gefiltert werden, und empfiehlt einen Composite-Index:

CREATE INDEX idx_orders_user_status_date
ON orders (user_id, status, created_at DESC);

Mit diesem Index sinkt die Query von einem Full-Table-Scan auf einen Index-Scan über wenige Rows.

Query-Analyse mit EXPLAIN

Noch besser: EXPLAIN-Output direkt übergeben. PostgreSQL, MySQL und SQLite haben alle einen EXPLAIN-Befehl:

psql -c "EXPLAIN ANALYZE SELECT ..." | claude "Was ist das Performance-Problem in diesem Query-Plan?"

Claude Code liest Seq Scans, Hash Joins, und Nested Loops und erklärt präzise, welcher Teil des Plans ineffizient ist und warum. Kein manuelles Interpretieren von Row-Estimates und Cost-Werten mehr.

Das N+1-Problem in ORMs

Das N+1-Problem ist das häufigste Performance-Anti-Pattern in Anwendungen mit ORM (Django ORM, ActiveRecord, Hibernate, Sequelize). Es entsteht, wenn man für eine Liste von Objekten jede verknüpfte Ressource einzeln lädt:

claude "Schau dir diesen Django-View an und identifiziere N+1-Probleme.
Zeige die optimierte Version mit select_related oder prefetch_related:

def order_list(request):
    orders = Order.objects.filter(user=request.user)
    result = []
    for order in orders:
        result.append({
            'id': order.id,
            'customer': order.customer.name,    # N+1: 1 Query pro Order
            'items': [i.name for i in order.items.all()],  # N+1: 1 Query pro Order
        })
    return JsonResponse({'orders': result})"

Claude Code zeigt die optimierte Version, die statt N+2 Queries nur 3 ausführt:

def order_list(request):
    orders = Order.objects.filter(user=request.user)\
        .select_related('customer')\
        .prefetch_related('items')
    result = []
    for order in orders:
        result.append({
            'id': order.id,
            'customer': order.customer.name,
            'items': [i.name for i in order.items.all()],
        })
    return JsonResponse({'orders': result})

N+1 ist schwer zu sehen: Das Problem entsteht nicht im ORM-Call selbst, sondern in der Schleife danach. Ein Tool wie Django Debug Toolbar oder das Logging von SQL-Queries hilft beim Erkennen. Frag Claude Code: "Wie aktiviere ich SQL-Logging in [Framework], damit ich N+1-Probleme sehe?"

4. Caching-Strategien

Caching ist die schnellste Performance-Verbesserung — aber nur, wenn man die richtige Ebene wählt. In-Memory-Cache, Redis, HTTP-Caching und CDN haben verschiedene Trade-offs. Claude Code hilft dabei, die richtige Strategie für den jeweiligen Use Case zu wählen und korrekt zu implementieren.

In-Memory-Caching

Für Werte die teuer zu berechnen sind und sich selten ändern, ist In-Memory-Caching die einfachste Lösung. Python hat functools.lru_cache, JavaScript Map-basierte Caches:

claude "Diese Funktion wird tausende Male pro Sekunde aufgerufen und
liefert für gleiche Inputs immer dasselbe Ergebnis. Wie implementiere
ich einen effizienten In-Memory-Cache mit TTL?

def calculate_user_tier(user_id: int) -> str:
    user = db.fetch_user(user_id)
    purchases = db.fetch_purchase_history(user_id, days=90)
    return compute_tier(user, purchases)"

Claude Code zeigt eine Cache-Implementierung mit TTL und automatischer Invalidierung, angepasst an den konkreten Code:

from functools import lru_cache
from cachetools import TTLCache
import threading

_cache = TTLCache(maxsize=10_000, ttl=300)  # 5 Minuten TTL
_lock = threading.Lock()

def calculate_user_tier(user_id: int) -> str:
    with _lock:
        if user_id in _cache:
            return _cache[user_id]
    user = db.fetch_user(user_id)
    purchases = db.fetch_purchase_history(user_id, days=90)
    result = compute_tier(user, purchases)
    with _lock:
        _cache[user_id] = result
    return result

Redis für verteilte Systeme

Sobald mehrere Server-Instanzen laufen, reicht In-Memory-Cache nicht mehr — jede Instanz hat ihren eigenen, inkonsistenten Stand. Redis ist die Standardlösung für verteiltes Caching:

claude "Wir haben eine Flask-App auf 4 Pods. Die calculate_user_tier-Funktion
muss gecacht werden, aber konsistent über alle Pods. Zeig mir eine Redis-Cache-
Implementierung mit Cache-Stampede-Schutz."

Claude Code erklärt den Cache-Stampede (wenn der Cache abläuft und alle Pods gleichzeitig die teure Berechnung starten) und zeigt die Lösung mit einem Lock-Pattern:

import redis
import json
import time

r = redis.Redis(host='redis', port=6379, decode_responses=True)
CACHE_TTL = 300
LOCK_TTL = 10

def calculate_user_tier(user_id: int) -> str:
    cache_key = f"user_tier:{user_id}"
    lock_key = f"lock:user_tier:{user_id}"

    cached = r.get(cache_key)
    if cached:
        return json.loads(cached)

    # Cache-Stampede-Schutz: nur ein Worker berechnet neu
    if r.set(lock_key, "1", nx=True, ex=LOCK_TTL):
        try:
            user = db.fetch_user(user_id)
            purchases = db.fetch_purchase_history(user_id, days=90)
            result = compute_tier(user, purchases)
            r.setex(cache_key, CACHE_TTL, json.dumps(result))
            return result
        finally:
            r.delete(lock_key)
    else:
        # Anderer Worker rechnet gerade — kurz warten, dann nochmal prüfen
        time.sleep(0.1)
        return calculate_user_tier(user_id)

HTTP-Caching und Cache-Control

Für API-Responses und statische Ressourcen ist HTTP-Caching die effizienteste Lösung, weil sie Anfragen vollständig vermeidet:

claude "Welche Cache-Control-Header sind für diese Ressourcentypen optimal?
- Produktbilder (ändern sich selten)
- API-Response /api/products (ändert sich täglich)
- Nutzerspezifische API-Response /api/user/cart (ändert sich häufig)
- Static Assets (JS/CSS mit Content-Hash im Filename)"

Claude Code gibt für jeden Typ eine begründete Empfehlung — und erklärt den Unterschied zwischen max-age, s-maxage, stale-while-revalidate und no-cache vs. no-store.

5. Frontend-Performance und Core Web Vitals

Google bewertet Seiten nach Core Web Vitals: Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS) und Interaction to Next Paint (INP). Schlechte Werte kosten Ranking. Claude Code hilft dabei, Bundle-Size zu reduzieren, Lazy Loading korrekt zu implementieren und die Vitals zu verbessern.

Bundle-Size analysieren und reduzieren

npx webpack-bundle-analyzer stats.json | claude "Welche Pakete machen
den größten Teil des Bundles aus und wie kann ich sie reduzieren?"

Oder direkt mit dem Build-Output:

npm run build 2>&1 | claude "Das Bundle ist 2.4 MB. Welche Optimierungen
empfiehlst du, um es unter 500 KB zu bringen?"

Claude Code liest die Package-Größen, identifiziert die größten Kandidaten für Tree-Shaking oder Code-Splitting, und gibt konkrete Empfehlungen: welche Pakete durch kleinere Alternativen ersetzt werden können (moment.js durch date-fns, lodash durch native Methoden), und wo Dynamic Imports sinnvoll sind.

Lazy Loading und Code-Splitting

claude "Ich habe eine React-App mit 15 Routes. Nur die Home-Page ist
kritisch für den First Load. Zeig mir, wie ich React.lazy und Suspense
für die anderen Routes einsetze, um den initialen Bundle zu halbieren."

Claude Code liest die Router-Konfiguration und gibt die konkrete Umbauanleitung — nicht generisch, sondern angepasst an die vorhandenen Import-Pfade und Component-Namen.

Core Web Vitals verbessern

LCP-Probleme entstehen meist durch große, unoptimierte Bilder oder render-blockierendes JavaScript. CLS durch Elemente ohne definierte Größen. INP durch lange JavaScript-Tasks im Main Thread.

claude "PageSpeed Insights meldet LCP 4.2s (sollte unter 2.5s sein).
Der LCP-Kandidat ist das Hero-Image. Was sind die häufigsten Ursachen
und welche Optimierungen soll ich zuerst prüfen?"

Für ein vollständiges Audit kannst du die Lighthouse-JSON direkt übergeben:

lighthouse https://example.com --output json --output-path report.json
cat report.json | claude "Was sind die drei wichtigsten Findings aus diesem
Lighthouse-Report und wie behebe ich sie?"

LCP-Schnellcheck: Das häufigste LCP-Problem ist ein Bild ohne fetchpriority="high" und ohne preload-Link im <head>. Frag Claude Code: "Prüf mein HTML-Template darauf, ob das LCP-Element korrekt priorisiert wird."

6. Concurrency und asynchrone Verarbeitung

Moderner Code ist selten single-threaded. I/O-bound Operationen — API-Calls, Datenbankzugriffe, Datei-Reads — können parallel ausgeführt werden. CPU-bound Operationen können auf Worker-Threads oder Prozesse ausgelagert werden. Claude Code erkennt, wo sequenzielle Ausführung unnötig Wartezeit erzeugt.

Sequenzielle I/O parallelisieren

claude "Dieser Code ruft drei externe APIs sequenziell auf.
Wie stelle ich auf parallele Ausführung um?

async function getDashboardData(userId) {
  const user = await fetchUser(userId);
  const orders = await fetchOrders(userId);
  const recommendations = await fetchRecommendations(userId);
  return { user, orders, recommendations };
}"

Claude Code erkennt, dass die drei Calls unabhängig voneinander sind, und gibt die optimierte Version mit Promise.all:

async function getDashboardData(userId) {
  const [user, orders, recommendations] = await Promise.all([
    fetchUser(userId),
    fetchOrders(userId),
    fetchRecommendations(userId),
  ]);
  return { user, orders, recommendations };
}

Statt dreier sequenzieller Warzeiten (z.B. 200ms + 150ms + 180ms = 530ms) reduziert sich die Gesamtwartezeit auf das Maximum der drei (180ms). Das ist ohne Code-Änderung am Ergebnis eine fast 3x-Beschleunigung.

Python: asyncio und Concurrent.futures

claude "Ich habe eine Python-Funktion die für 500 URLs jeweils einen
HTTP-Request macht. Aktuell sequenziell: ~8 Minuten. Zeig mir die
asyncio-Version mit einem sinnvollen Concurrency-Limit."

Claude Code gibt die asyncio-Implementierung mit einem Semaphor als Concurrency-Limit:

import asyncio
import aiohttp

async def fetch_urls(urls: list[str], max_concurrent: int = 50) -> list[dict]:
    semaphore = asyncio.Semaphore(max_concurrent)

    async def fetch_one(session: aiohttp.ClientSession, url: str) -> dict:
        async with semaphore:
            async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
                return {"url": url, "status": resp.status, "body": await resp.text()}

    async with aiohttp.ClientSession() as session:
        tasks = [fetch_one(session, url) for url in urls]
        return await asyncio.gather(*tasks, return_exceptions=True)

500 sequenzielle Requests bei 1s durchschnittlicher Latenz: 8+ Minuten. 500 parallele Requests mit 50er Concurrency-Limit: unter 15 Sekunden.

Background Jobs und Queues

Für Operationen die zu lang dauern, um synchron im Request ausgeführt zu werden (E-Mails versenden, Berichte generieren, Videos verarbeiten), empfiehlt Claude Code den Übergang zu einem Queue-System:

claude "Unser API-Endpoint /api/export generiert einen Report und
braucht 20-45 Sekunden. Das führt zu Timeouts. Wie strukturiere
ich das als Background-Job mit Status-Polling? Wir nutzen FastAPI
und haben Redis verfügbar."

Claude Code zeigt das vollständige Pattern: einen Endpoint der den Job startet und eine Job-ID zurückgibt, einen Background Worker der den Job ausführt, und einen Status-Endpoint für das Frontend.


Performance-Optimierung ist ein iterativer Prozess: messen, analysieren, optimieren, messen. Claude Code beschleunigt jeden dieser Schritte — besonders die Analyse, die normalerweise am meisten Zeit kostet. Zwei verwandte Artikel:


Claude Code Mastery — von Performance bis zum produktiven Agenten

Performance-Optimierung ist eine Stärke von Claude Code — aber nicht die einzige. Im Kurs lernst du Agents, MCP-Server, Hooks, Multi-Agent-Workflows und mehr. Vollständig auf Deutsch, einmalig bezahlt.

Jetzt starten — ab €29 → Basis ab €29 · Pro ab €49 · Kein Abo · 14 Tage Rückgaberecht

Kurs · Claude Code Mastery

Von Profiling zum produktiven AI-Agenten

Performance. Debugging. Agents. MCP. Hooks. Multi-Agent-Workflows. Alles auf Deutsch, einmalig bezahlt — kein Abo, keine Plattformabhängigkeit.

Jetzt einsteigen → Kursübersicht ansehen →

Basis ab €29 · Pro ab €49 · Kein Abo · 14 Tage Rückgaberecht