Query cost guardrails
Every query is estimated with EXPLAIN ESTIMATE (cached 60 s per plan) and checked against the project's budgets before it runs.
Budgets:
PUT|GET|DELETE /v1/projects/{prj}/query-budgets. Scopesproject,user,agent; limitsmax_bytes_per_queryandmax_bytes_per_day; modewarn(flag the response) orenforce(422query_too_expensivewith the estimate and a hint to narrow the range). Agents have their own budgets, separate from users.Attribution: each ClickHouse query carries
{project, user, route, class, dashboard, tile, rule, agent}inlog_comment; onequery_cost_v1row is written per query by a bounded async batcher (rows are dropped, never blocked on, when the queue is full).Reports:
GET /v1/projects/{prj}/query-cost?group_by=user|route|dashboard&from&to.Slow queries: the
slow_queriesview overquery_cost_v1(5 s and over).Result cache: in-memory LRU (256 MiB), key includes the project; 60 s TTL for ranges that touch now, 1 h for historical ranges; errors and partial results are never cached;
?no_cache=1bypasses it. Ranges over 6 h are split into step-aligned 24 h chunks.