yugabyte/yugabytedb-skills/yb-perf

Claude Code and agent skill by yugabyte/yugabytedb-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Checks the YugabyteDB-specific performance traps that general database and monitoring knowledge misses, and the evidence required before concluding. Use when an app, site or database on YugabyteDB is slow, latency is up, p99 regressed, someone asks "is the database the cause?", or a universe needs a health check or performance review - and for the specifics - a slow query, an EXPLAIN (ANALYZE, DIST) plan, pg_stat_statements, lock contention or retries, ASH wait events, a node hotspot, leader or tablet skew, CPU, disk or memory pressure, tablet limits, Prometheus / YBA metrics. Covers both the SQL layer and the metrics layer, with read-only one-call check scripts, and works with whatever access exists - live SQL, Prometheus / YBA metrics, or pasted output - before naming a root cause or ruling the database out.

Install

npx vskill@latest install yugabyte/yugabytedb-skills/yb-perf

SKILL.md

YugabyteDB performance: must-checks

You already know how to diagnose a slow Postgres-style system and read a monitoring stack. This skill adds only what is different on YugabyteDB, plus the rules that stop the common wrong conclusions. It covers two layers: SQL / session (S rows) and metrics (M rows).

Process (any slowness question)

  1. Scope first: one path slow, or many unrelated paths slow at once? Use the app's

per-endpoint / activity latency if available, else the spread across pg_stat_statements. Many at once → node, quorum or resource. One path → a query: find the statements that path runs. The top total_exec_time query is often a healthy batch job. This gate decides between layers: a node problem slows every path that touches that node. If the complaint is one path and other paths run at normal latency, the cause is on that path (its statements, its connections, its client), and any node finding is secondary.

  1. Run the one-call checks in the order the scope sets, from this skill's directory,

before any hand-written query. They are cheap and read-only, and each layer is blind to causes the other sees (metrics miss scan amplification, connection churn / catalog warm-up, unindexed FK cascades; SQL misses a CPU-starved node and leader skew).

  • One path slow → scripts/must-check.sql first, and explain that path from its

statements, connections and client. Run scripts/metrics-check.sh only if the path's statements don't explain it, and treat a node finding as secondary unless other paths are slow too.

  • Many paths slow, or metrics are all you have → scripts/metrics-check.sh first, then

scripts/must-check.sql (if reachable) to rule out a query driving the node.

  • Scope unknown → ask, or find it (app per-activity latency, the pgss spread) before

choosing. If a layer is unreachable, say so in the report. With pasted evidence, apply the checks to what you have.

  • SQL: run it once, as one call, with ysqlsh -f <path> or the session wrapper you were given.
  • Metrics: bash <path>/metrics-check.sh http://<prometheus>:9090. On YBA set the scope first:

YB_SEL='node_prefix="<prefix>",export_type="tserver_export"' and YB_MASTER_SEL='node_prefix="<prefix>",export_type="master_export"' (header of the script has the rest). It prints per-node tables, flags any node at 2× or more its peers' median, and ends with a per-node verdict.

  1. Drill into the layer the evidence points at; confirm with the other (conflicts in

metrics → retries / ASH in SQL; a uniform SQL latency rise → the per-node M rows).

  1. Rank causes by the latency the user feels, not by database time spent. Waits (row

locks, conflict retries, queueing) are excluded from pg_stat_statements timings, so a 1 ms statement can be the 500 ms problem.

  1. Break every latency, CPU or queue metric down per node before reading an aggregate. On

RF3, one bad node is diluted about 3× in a cluster average. Compare each node with its peers; the outlier is the finding.

  1. **When the complaint is broad (many paths slow) and one node is a large, new latency

outlier, explain that node first. A node leading the hottest tablets routinely runs 2-3× its peers in a healthy cluster, so a modest ratio is a lead, not a cause, and never outranks a SQL finding that explains the path the user named. Name the outlier's ceiling: CPU limit, disk, or a noisy neighbour. Low CPU on the slow node does not** rule out CPU: a capped node cannot use more, so compare its usage with its limit (M3c, or the container / VM size). A busy table on that node is the cause only if its load is new or abnormal for that table -- table load sits where the table's leaders are, and the same load on a healthy node would be fast.

  1. **Before writing "no database-side cause" or "infrastructure is healthy", list which

must-checks you ran and what each showed.** Any check you couldn't run is an open gap, not a clean result. A node that is up is not a node that is healthy.

Must-checks: SQL / session

#CheckWhereMeans
S1conflict_retries / read_restart_retries per call > 0.1pgssContention, or lock waits under Read Committed (a wait becomes a retry). A fast mean with retries is waiting, not fast.
S2Transaction age ≫ current statement time; idle in transactionpg_stat_activitySomething holds locks across other work. Look at what the same transaction does after its first write.
S3pg_locks shows nothingpg_locksNot proof of no blocking. It hides transactions younger than yb_locks_min_txn_age (default 1 s). SET yb_locks_min_txn_age = 0 in your session (changes no data), and sample more than once.
S4Same statement text in two pgss rows; or mean_plan_time ≫ mean_exec_time on a point querypgssPer-connection catalog warm-up: the app opens a connection per request. Confirm with one fresh-session timing. Fix: connection pooling, not the query.
S5docdb_rows_scanned / rows ≫ 1; or Storage Rows Scanned = 2× rows returnedpgss / EXPLAIN (ANALYZE, DIST)Scan amplification (missing index or blocked pushdown), or a non-covering index (index + table read). For an aggregate (count(*), GROUP BY) compare scanned-per-call with the table's row count instead. `docdb_rows_*` are filled only while `yb_enable_pg_stat_statements_rpc_stats` was on in the workload's sessions (off by default on 2025.2): if it was off, S5 is a gap, not a pass -- use EXPLAIN (ANALYZE, DIST) on a read.
S6Latency high but scan ratio ≈ 1 (measured -- see S5) on a queue-like or delete-heavy tablepgss + M7Tombstones from deletes: YugabyteDB counts live rows, so the plan looks clean.
S7PRIMARY KEY (ts ASC ...) or another range key on a monotonic valueschemaAll inserts hit the last range tablet. More tablets won't fix it; a hash-prefixed key will.
S8yb_servers() count, follower_lag_ms, uniform latency rise across unrelated statementsSQL / M1, M6Node or infrastructure event, not a query defect. Don't invent a SQL cause; find the node in the M rows.
S9pg_class.reltuples = -1 (PG15-based 2025.1+); reltuples = 0 on PG11-based 2024.x and earlier, where 0 can also be an empty tablecatalogNever analysed: the planner is guessing. Cluster-wide; pg_stat_user_tables timestamps are per node.

Must-checks: metrics (per node)

#CheckMeans
M1Targets up, tserver and masterFewer than expected = a node is down.
M2Tserver Read / Write RPC latency (`rpc_latency{service_method="Read"\"Write"}`): mean and p99One node ≫ peers = that node is slow (CPU-starved, disk, noisy neighbour).
M3CPU per node, against its limit: process, then host or container, then the limit / throttlingA node pinned at a lower ceiling than its peers is throttled or undersized. Low usage on the slow node does not clear it (step 6).
M4WAL sync latencyDisk / fsync problem on that node.
M5Leaders, tablet peers, share of the tablet limit, limit rejectionsLeader skew concentrates load; peers near the limit block creates and splits.
M6Follower lag, all_operations_inflight, memory-pressure / SST / RPC-queue rejectionsLag is often a symptom; rejections are the cause.
M7RocksDB seek/next per op, per table_nameHigh seek/next for flat row counts = tombstones (delete-heavy tables; S6). Heavy load on a table is not itself a finding (step 6).
M8rocksdb_stall_micros, queued compactionsWrite stalls from compaction debt.
M9Master RPC latency and queue rejectionsCatalog / DDL / heartbeat pressure on the master leader.
M10Transaction conflicts, wait-queue waitersContention: confirm in SQL (S1 retries, scripts/ash.sql).
M11App metrics, if exported: per-endpoint or activity latencyConfirms the scope (step 1) from the user's side.

Safety

  • Read-only by default. Anything that changes the system (DDL, cancelling transactions,

statistics resets, GUC / GFlag changes) is proposed for approval, not run.

  • EXPLAIN ANALYZE executes the statement -- never run it on INSERT/UPDATE/DELETE (or any

write); use plain EXPLAIN, or an equivalent SELECT.

Scripts and references

  • scripts/must-check.sql -- run first for SQL: S1-S5, S8, S9 plus context (version, pgss window), p99/p50, unindexed foreign keys and abnormal terminations.
  • scripts/metrics-check.sh -- run first for metrics: M1-M10 in one Prometheus pass (read-only HTTP GETs; Read and Write mean and p99), YBA or self-managed selectors. M11 (app metrics) is a reminder only: check it yourself.
  • scripts/ash.sql -- when time goes to waits: ASH wait breakdown, top query_id, hot tablets, zone split (-v window='30 minutes').
  • scripts/all-nodes.sh -- pgss, pg_stat_activity, pg_locks and ASH are per node: run either SQL file on every node (--help for host mapping, --exec, --kube).
  • references/yb-facts.md -- read before relying on a column, GUC, default, version gate or wait-event name: pgss, stats, locks, EXPLAIN, hints, query diagnostics, ASH.
  • references/access.md -- read when there is no direct ysqlsh: YBA Kubernetes, Aeon, paste mode, CSV exports.
  • references/metric-names.md -- read before writing PromQL beyond the script: exact metric and label names, YBA vs self-managed labels.
  • references/yb-metric-facts.md -- read when interpreting a metric value: leader counts, percentiles, tablet limits and splitting, metric sources (YBA, node endpoint, Aeon).
  • YBA's Prometheus listens on port 9090 of the YBA host; node_prefix is the universe's universeDetails.nodePrefix (YBA API GET /api/v1/customers/{cUUID}/universes/{uUUID}). For more, if the yba-api skill is installed, see its Prometheus reference.

Report

  • One primary cause tied to the complaint, with its evidence (per-node evidence, naming the

node or component, when it is an infrastructure cause).

  • Then secondary findings, explicitly subordinated.
  • Then the must-checks you ran (S and M), what each showed, and the gaps: checks or whole

layers you couldn't reach.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/yugabyte/yugabytedb-skills/yb-perf/badge)](https://verified-skill.com/skills/yugabyte/yugabytedb-skills/yb-perf)

Something wrong with this skill or its page? Tell us.