Skip to main content

mz-query-tracing

Debug SQL execution time via distributed tracing (OpenTelemetry / Tempo). Trigger: "why is this query slow", "where is the time going", "this SELECT takes forever", or latency breakdown for SQL statement. Also tracing queries, span analysis, Tempo traces, trace IDs, opentelemetry_filter.

Quellinformationen

Repository
MaterializeInc/materialize
Letzte Quellaktivität
7. Mai 2026 um 16:53
Erkannte Sprache von SKILL.md
Englisch
Sterne
6.383
Forks
515

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
2 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
mz-query-tracing
description
Debug SQL execution time via distributed tracing (OpenTelemetry / Tempo). Trigger: "why is this query slow", "where is the time going", "this SELECT takes forever", or latency breakdown for SQL statement. Also tracing queries, span analysis, Tempo traces, trace IDs, opentelemetry_filter.
# Query Tracing Skill Use distributed tracing (OpenTelemetry / Tempo) to understand where time is spent during SQL statement execution in a local Materialize instance. For background on Materialize's tracing infrastructure (span levels, filtering, `#[tracing::instrument]`, distributed context propagation), see `doc/developer/tracing.md`. ## Important: Use Optimized Builds **Always trace `--optimized` builds.** Debug builds introduce significant artifacts — unoptimized code, extra debug checks, and inflated self-times that don't reflect production behavior. Tracing a debug build can be misleading because time may appear in places that are negligible in release builds. ```bash bin/environmentd --optimized --monitoring ``` The `--optimized` build takes longer to compile but produces traces that accurately represent where time is actually spent. ## Prerequisites The local monitoring stack (Tempo + Grafana + Prometheus) and `environmentd` with tracing enabled must be running. All network calls require `dangerouslyDisableSandbox`. **Important: Start the monitoring stack _before_ environmentd.** If Tempo is not running when environmentd starts sending spans, those spans are lost — they will not be retroactively captured. ### 1. Start the monitoring stack ```bash bin/mzcompose --find monitoring run default ``` Wait for Tempo to be ready: ```bash # Poll until Tempo is accepting requests for i in $(seq 1 30); do curl -s -o /dev/null -w "%{http_code}" http://localhost:3200/ready | grep -q 200 && break sleep 5 done ``` ### 2. Start environmentd with tracing ```bash bin/environmentd --optimized --monitoring ``` Or with the trace filter pre-set: ```bash bin/environmentd --optimized --reset --monitoring -- --system-parameter-default='opentelemetry_filter=debug' ``` ### 3. Verify both services are running Before tracing, confirm the stack is healthy: ```bash # Tempo accepting traces? curl -s -o /dev/null -w "%{http_code}" http://localhost:3200/ready # environmentd listening? lsof -tiTCP:6875 -sTCP:LISTEN ``` ### 4. Set the trace filter at runtime (if not set at startup) Connect as `mz_system` and set the OpenTelemetry filter: ```bash psql -U mz_system -h localhost -p 6877 materialize -c "ALTER SYSTEM SET opentelemetry_filter = 'debug';" ``` `debug` is a good starting filter. For even more detail, use `trace` (but expect much more data). You can also target specific modules: ``` ALTER SYSTEM SET opentelemetry_filter = 'mz_adapter::coord=trace,debug'; ``` ## Workflow: Trace a Query ### Step 1: Run the query and capture the trace ID Use `psql` with `emit_trace_id_notice` enabled. **Important:** Use separate `-c` flags for SET and the query, since DDL statements (CREATE, DROP, ALTER) cannot run inside an implicit transaction block: ```bash psql -U materialize -h localhost -p 6875 materialize \ -c "SET emit_trace_id_notice = true;" \ -c "<YOUR SQL STATEMENT HERE>;" ``` The output will contain NOTICE lines with trace IDs — one per statement. The SET statement gets its own trace ID; the second trace ID is the one you want: ``` SET NOTICE: trace id: fd2f69eb059e4823d8d48a87ccab8f6f NOTICE: trace id: 984bd8c69f99703243d350e14b02caea CREATE TABLE ``` The trace ID for the query is the **last** one before the statement result. To extract the trace ID programmatically: ```bash OUTPUT=$(psql -U materialize -h localhost -p 6875 materialize \ -c "SET emit_trace_id_notice = true;" \ -c "CREATE TABLE foo (id INT);" 2>&1) TRACE_ID=$(echo "$OUTPUT" | grep "trace id:" | tail -1 | sed 's/.*trace id: //') echo "Trace ID: $TRACE_ID" ``` ### Step 2: Wait for spans to be flushed Spans are batched before export (default 5s delay, configured in `--opentelemetry-sched-delay`). Wait ~10 seconds after the query completes. ### Step 3: Fetch the trace from Tempo Query the Tempo HTTP API on port 3200. Retry if needed — spans may still be in flight: ```bash sleep 10 # Retry loop — first attempt often gets "trace not found" for i in $(seq 1 5); do RESP=$(curl -s http://localhost:3200/api/traces/$TRACE_ID) if echo "$RESP" | grep -q "batches"; then echo "$RESP" > /tmp/claude-1000/trace.json echo "Trace fetched ($(echo "$RESP" | wc -c) bytes)" break fi echo "Trace not ready, retrying... ($i/5)" sleep 5 done ``` ### Step 4: Analyze the trace The Tempo API returns traces in OTLP JSON format. **Important:** Span IDs and parent span IDs are base64-encoded, not hex. The analysis script handles this. Use the `trace_tree.py` script in this skill directory to analyze traces: ```bash python3 .claude/skills/mz-query-tracing/trace_tree.py /tmp/claude-1000/trace.json "My Query" ``` ## Interpreting Results - **Self-time** is where actual work happens. A span with 100ms duration but 0ms self-time is just a wrapper — its children do all the work. - **`group_commit_apply::append_fut`** — Persist append operations, often dominant for DDL. Time here is spent writing to the durable log. - **`catalog::transact_inner`** — Catalog transaction processing. High self-time means catalog state manipulation. - **`oracle::write_ts` / `oracle::apply_write`** — Timestamp oracle calls to CockroachDB. Each is a round-trip. - **`consensus::compare_and_set` / `consensus::scan`** — Persist consensus operations (also CockroachDB round-trips). - **`coord::check_consistency`** — Post-DDL consistency check. Self-time here is pure computation. - **Sequential vs. concurrent children** — children with overlapping time ranges are concurrent; non-overlapping are sequential. - **Code locations** in `[src/...]` brackets let you jump directly to the source code. - For spans not listed above, **read the source code** at the location shown in the `[src/...]` bracket to understand what the span does and why it's taking time. ## Tips - **Use `--optimized` builds.** Debug builds inflate self-times with unoptimized code paths and extra debug checks (e.g., `check_consistency` may appear much larger than in production). Always trace optimized builds for meaningful results. - **Start monitoring before environmentd.** Spans emitted before Tempo is ready are silently dropped. If you restart environmentd, make sure Tempo is still running. - If traces are empty or incomplete, the `opentelemetry_filter` may be too restrictive. Try `debug` or even `trace`. - The first fetch after a query often returns `trace not found`. The default batch delay is 5s, but ingestion adds latency. Always use a retry loop. - Tempo retains traces for only 15 minutes by default (configured in `misc/monitoring/tempo.yml`). Fetch traces promptly. - To search for recent traces: `curl -s "http://localhost:3200/api/search?limit=10"` - You can also view traces in Grafana at http://localhost:3000 by searching for the trace ID in the Tempo datasource explore view. - For comparing before/after a code change, trace the same query on both builds and compare the self-time rankings side by side.
Auf GitHub ansehen