Skip to main content
Minimum Startree version needed for this feature is 0.15

Overview

Query Logger captures a record of the queries your Pinot cluster serves and stores it in a queryable Pinot table called system_query_log. By default it keeps the queries worth investigating, slow ones and failed ones, and you can switch it to capture every query (see What gets captured). Instead of hunting through broker logs, you run ordinary SQL against your own query history to answer questions like:
  • Which queries are the slowest or the most expensive right now?
  • Which query patterns (templates) dominate load?
  • Which queries are scanning too much data, hitting limits, or erroring?
  • How has a specific query’s latency or resource usage changed over time?
Each row = one query executed by a broker, enriched with timing, data-scan counts, CPU/memory usage, and the query text itself.

How it’s enabled

On current StarTree releases, Query Logger is on by default. StarTree provisions the system_query_log table and configures the capture pipeline and storage location for you, so you can query the table like any other (via the Query Console or the query API) with no client-side setup. On older releases it is off by default; contact StarTree Support to enable it for your cluster. To turn capture off, set querylog.enabled to false (see Configuration). The change applies without restarting brokers, and data already captured stays until retention removes it.

Browse query history in the Data Portal

You don’t have to write SQL to look through system_query_log. In the Data Portal, open Monitoring → Query Insights. The History tab reads the same table and shows totals for success, partial-response and failed queries, p99 latency, query-rate and latency charts, and a sortable list of the captured queries. Filter by time range, engine, status or table.
Query Insights History tab in the Data Portal
The counts cover captured queries only. With the default capture settings that means slow and failed queries, not your total query volume. History refreshes about every 10 minutes, the same delay as the table itself. The Insights tab goes a step further. On a schedule you pick, it sends the slowest queries in this log through Query Analyzer and posts the recommendations to Slack, email or both. See Set Up Proactive Analysis.

What gets captured

By default, a query is captured when either of these is true:
  • It took 1 second or longer (timeUsedMs >= 1000).
  • It failed with an error.
Fast, successful queries are not stored. This keeps the table focused on the queries you are likely to investigate, and keeps its storage footprint small on busy clusters.
Clusters that had Query Logger enabled before this default was introduced keep capturing every query after upgrading. Set querylog.capture.threshold.enabled explicitly to choose either behavior.
A few kinds of query are left out by default:
  • Queries against system_query_log itself, such as the ones you run while browsing query history. This stops the log from filling up with its own lookups.
  • StarTree health checks and uptime probes. These are identified by the client that sends them, not by the SQL, so your own queries are never excluded by accident.
  • Queries you opt out individually. Prepend SET skipQueryLog=true; to a statement you don’t want recorded, such as a high-frequency health check of your own:
    This only affects logging. The query still runs and returns results normally.

Configuration

Query Logger settings are cluster configs. Change them with the controller’s cluster-config API:
To return a setting to its default, delete it:

Capture settings

These apply to new queries without restarting brokers.
Setting querylog.capture.threshold.errors to false together with querylog.capture.threshold.latency.ms set to -1 leaves nothing to capture. Use querylog.enabled to turn capture off instead.
The table setting is an allowlist only. There is currently no setting to capture every table except a few.

Table settings

These control the system_query_log table itself.
Table settings take effect when the table is first created. Changing them on a cluster where system_query_log already exists does not update the table. To change retention, the storage cap, or the tenant on an existing cluster, contact StarTree Support.
Set the tenants before the table is created if your cluster has no DefaultTenant, or if you want query history kept off the servers that handle production traffic.

The data: key fields

The table has ~70 columns. The ones you’ll use most, grouped by purpose: Identity & context Timing & result Data scanned (why a query is expensive) Resource usage Limit / safety flags (booleans): numGroupsLimitReached, groupsTrimmed, maxRowsInJoinReached, maxRowsInWindowReached, maxRowsInDistinctReached — these tell you a query hit a guardrail and may have returned trimmed/partial data. Deep diagnostics: stageStats (JSON, multi-stage per-operator stats), serverStats, traceInfo, responseMetadataJson — for detailed drill-down.
* queryHash is populated only when query fingerprinting is enabled for your cluster; otherwise it may be empty. Ask StarTree Ops if you plan to rely on it.

Sample queries

All examples filter to the last 24 hours using logTimestampMs. Adjust the window as needed. Always keep a time filter on these queries (see Limitations & caveats).
Top 10 slowest queries (last 24h)
Top 10 most CPU-expensive queries
Worst query patterns — aggregate by template (find the query shapes driving load)
Heavy scanners (candidates for a better index)
Failed / errored queries
Queries that hit a limit guardrail (possibly returning trimmed results)
Query volume & latency by table

How the data is kept tidy

You don’t manage any of this — it’s handled automatically — but it’s useful to know:
  • Automatic segment compaction. The pipeline lands data as many small segments (one every few minutes per broker). A background merge/rollup job runs on a schedule and compacts those small segments into fewer, larger ones, keeping the total segment count bounded as the table grows. No action is required on your part.
  • Automatic retention. Data older than the configured retention window is dropped automatically, so the table stays within its storage budget.

Limitations & caveats

⚠️ It consumes storage on your cluster. system_query_log is a real Pinot table — its segments occupy disk on your servers. StarTree keeps it bounded with an automatic retention window (older data is dropped, 7 days by default) and a storage quota (300 GiB by default), and the background merge job (above) keeps the segment count in check, so the footprint stays finite. When the table reaches its quota, newly captured queries stop landing until retention frees space; existing history is not deleted early. High-QPS clusters, or clusters that capture every query, generate more log data; see Table settings and talk to StarTree Support if you need a longer window or expect large volume.
⚠️ Your analysis queries run on the same cluster. Queries against system_query_log execute on the same brokers and servers serving your production traffic and compete for the same resources. Always filter by logTimestampMs to a bounded window and avoid unbounded SELECT * scans, so debugging doesn’t add load to an already-busy cluster.
  • Near-real-time, not instant. Logged queries appear after background segment generation runs — expect a short delay (roughly 10–15 minutes) before a just-executed query is queryable. It’s for analysis and debugging, not live monitoring.
  • Long fields are truncated. query (4096 characters by default, see querylog.max.query.length), exceptions, serverStats, and traceInfo have maximum lengths; extremely large values are cut off.
  • One row per captured query. By default only slow and failed queries are stored (see What gets captured), so counts from this table are not total query volume unless capture is set to every query.
  • Best-effort capture. Under extreme broker load, or during an error storm where many queries qualify at once, some records may be dropped rather than slow down query serving.