← Zurück zum Blog
Performance

pg_slow_query_digest — Slow Queries finden, bevor sie zum Problem werden

ITUNIFIED • 2026-03-25 • 8 min Lesezeit

Was macht dieses Tool?

pg_slow_query_digest analysiert die in pg_stat_statements gesammelten Query-Statistiken und liefert eine nach Gesamtlaufzeit sortierte Liste der langsamsten Queries. Anders als ein einfaches SELECT * FROM pg_stat_statements ORDER BY total_exec_time DESC normalisiert das Tool die Ausgabe, berechnet Durchschnittswerte pro Aufruf und identifiziert Queries, die durch ihre Häufigkeit × Dauer die meisten Ressourcen verbrauchen.

Wie wird es aufgerufen?

Verbindung herstellen

Bevor ein Performance-Tool aufgerufen werden kann, muss eine Verbindung zur Zieldatenbank hergestellt werden. mcp-postgres unterstützt mehrere Datenbankprofile — ideal für Multi-Cluster-Setups:

● ● ●   Claude CLI — Verbindung
claude> Verbinde mit Profil "production-db"

▶ Calling tools...
→ pg_connect { "profile": "production-db" }

{
  "status": "connected",
  "database": "mcp_test",
  "version": "PostgreSQL 16.x",
  "host": "db.example.com"
}

Claude CLI (natürliche Sprache)

● ● ●   Claude CLI — Performance-Analyse
claude> Zeig mir die langsamsten Queries der letzten Stunde

▶ Calling tools...
→ pg_slow_query_digest {}

Hier sind die 2 langsamsten Queries nach Gesamtlaufzeit:

1. SELECT * FROM app.orders WHERE status = $1
   847 Aufrufe, Ø 12.4ms, Max 89.2ms, Gesamt: 10.5s
   → Kandidat für einen Index auf app.orders(status)

2. SELECT u.*, o.* FROM app.users u JOIN app.orders o...
   234 Aufrufe, Ø 8.7ms, Max 45.1ms, Gesamt: 2.0s
   → Join-Query mit hohem Row Count pro Aufruf (12)

MCP Protocol (programmatisch)

● ● ●   MCP Protocol — Performance-Analyse
// Programmatic invocation via MCP SDK
const result = await client.callTool("pg_slow_query_digest", {});

// Response:
{
  "slow_queries": [
    {
      "queryid": "9069661048250515891",
      "query_preview": "ANALYZE",
      "calls": "3",
      "total_time_ms": "1522.52",
      "mean_time_ms": "507.51",
      "stddev_ms": "59.49",
      "rows": "0",
      "pct_total": "46.76"
    },
    {
      "queryid": "-8526373234667933857",
      "query_preview": "DO $$\nBEGIN\n FOR i IN 1..20 LOOP\n PERFORM count(*) FROM perf.transactions...",
      "calls": "1",
      "total_time_ms": "510.39",
      "mean_time_ms": "510.39",
      "stddev_ms": "0.00",
      "rows": "0",
      "pct_total": "15.68"
    },
    {
      "queryid": "3348334810192286589",
      "query_preview": "INSERT INTO perf.transactions (transaction_id, account_id, ...)...",
      "calls": "1",
      "total_time_ms": "483.69",
      "mean_time_ms": "483.69",
      "stddev_ms": "0.00",
      "rows": "100000",
      "pct_total": "14.86"
    },
    {
      "queryid": "4800951176609648582",
      "query_preview": "ANALYZE perf.transactions",
      "calls": "1",
      "total_time_ms": "110.56",
      "mean_time_ms": "110.56",
      "stddev_ms": "0.00",
      "rows": "0",
      "pct_total": "3.40"
    }
  ]
}

Was passiert unter der Haube?

Das Tool führt folgende SQL-Query gegen pg_stat_statements aus:

-- Aggregierte Query-Statistiken aus pg_stat_statements
SELECT queryid, query AS query_preview, calls, total_exec_time AS total_time_ms, total_exec_time / calls AS mean_time_ms, stddev_exec_time AS stddev_ms, rows, total_exec_time * 100.0 / sum(total_exec_time) OVER() AS pct_total FROM pg_stat_statements WHERE calls > 0 ORDER BY total_exec_time DESC LIMIT 20;

Voraussetzung: Die Extension pg_stat_statements muss geladen sein (shared_preload_libraries = 'pg_stat_statements'). Das Tool prüft das automatisch und gibt einen klaren Fehler, wenn die Extension nicht verfügbar ist.

Ausgabe im Detail

  • queryid — Eindeutige ID der normalisierten Query aus pg_stat_statements
  • query_preview — Vorschau der Query (gekürzt bei langen Statements)
  • calls — Wie oft die Query seit dem letzten Reset aufgerufen wurde
  • total_time_ms — Gesamte Ausführungszeit in Millisekunden — die Sortiergrundlage
  • mean_time_ms — Durchschnittliche Ausführungszeit pro Aufruf
  • stddev_ms — Standardabweichung — hohe Werte deuten auf instabile Performance hin
  • rows — Gesamtanzahl zurückgegebener Zeilen
  • pct_total — Anteil an der Gesamtlaufzeit aller Queries in Prozent

Praxis-Tipp: Eine Query mit hohem total_ms aber niedrigem mean_ms wird nicht durch Einzelaufrufe langsam — sondern durch die schiere Menge an Aufrufen. Hier hilft oft ein Connection Pool oder Query-Caching, nicht ein Index.

Was testet die Testsuite?

Die Testsuite validiert pg_slow_query_digest gegen eine PostgreSQL 16-Instanz mit 300.000 Finanztransaktionen in der perf-Schema und realistischem Query-Muster:

● ● ●   vitest run — Testsuite
✓ pg_slow_query_digest > returns query statistics
✓ pg_slow_query_digest > includes calls, mean_ms, max_ms fields
✓ pg_slow_query_digest > sorts by total execution time descending
✓ pg_slow_query_digest > respects limit parameter

Test Files  1 passed (1)
     Tests  4 passed (4)
 Duration  312ms

Testdaten-Szenario

Die Seed-Datenbank enthält:

  • perf.transactions — 300.000 Zeilen (33 MB) mit Betrag, Währung, Status, Region, Kanal
  • pg_stat_statements — Automatisch befüllt durch die Testläufe selbst

Die Tests validieren, dass:

  1. Das Ergebnis ein Array mit Query-Objekten ist (nicht leer)
  2. Jedes Objekt die erwarteten Felder enthält (calls, mean_time_ms, pct_total)
  3. Die Sortierung nach total_time_ms absteigend korrekt ist
  4. Der limit-Parameter die Ergebnismenge begrenzt

Zusammenfassung

pg_stat_statements
Datenquelle
8
Ausgabefelder
4
Tests
read-only
Typ

pg_slow_query_digest ist das erste Tool, das ein DBA bei Performance-Problemen aufrufen sollte. Es ersetzt das manuelle Query-Graben in pg_stat_statements durch eine strukturierte, sortierte und sofort verwertbare Ausgabe.

In Kombination mit pg_index_advisor (→ fehlende Indizes) und pg_cache_hit_ratio (→ Buffer-Effizienz) bildet es den Kern des /pg-perf Workflow-Skills.

#postgresql#performance#slow-queries#pg_stat_statements#mcp

Bereit, PostgreSQL-Betrieb zu automatisieren?

Starten Sie mit dem Open-Source-Server oder kontaktieren Sie uns für die Enterprise-Plattform.