Basic Metric Query Patterns
Overview
This page covers the most common TimescaleDB SQL patterns for querying Arthur's pre-aggregated metrics store. Before using these patterns, read Metrics Overview & Data Model to understand the schema and the two available views (metrics_numeric_latest_version and metrics_sketch_latest_version).
For quantile queries, sketch function usage, and multi-metric joins, see Advanced SQL Patterns & Sketch Functions.
Discovery Queries
Before building a dashboard, find out which metrics exist for your model.
-- List all numeric metrics for a model
SELECT DISTINCT metric_name
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
ORDER BY metric_name;
-- List all sketch metrics for a model
SELECT DISTINCT metric_name
FROM metrics_sketch_latest_version
WHERE model_id = '{{your-model-uuid}}'
ORDER BY metric_name;Time-Series Queries
Retrieve the raw 5-minute buckets for a single metric over the last 24 hours:
SELECT
timestamp,
value
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'inference_count'
AND timestamp >= NOW() - INTERVAL '24 hours'
ORDER BY timestamp ASC;Downsampling
TimescaleDB's time_bucket() function lets you re-aggregate the 5-minute data into coarser intervals:
SELECT
time_bucket(INTERVAL '1 day', timestamp) AS bucket,
SUM(value) AS total_predictions
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'inference_count'
AND timestamp BETWEEN '{{dateStart}}' AND '{{dateEnd}}'
GROUP BY bucket
ORDER BY bucket DESC;Rate Calculations
Arthur stores component metrics separately. Divide them at query time to compute rates. Since Arthur reports raw counts (not rates), queries must perform the final division:
WITH hallucination_count AS (
SELECT
time_bucket(INTERVAL '1 day', timestamp) AS bucket,
SUM(value) AS total
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'hallucination_count'
AND timestamp BETWEEN '{{dateStart}}' AND '{{dateEnd}}'
GROUP BY bucket
),
total_count AS (
SELECT
time_bucket(INTERVAL '1 day', timestamp) AS bucket,
SUM(value) AS total
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'inference_count'
AND timestamp BETWEEN '{{dateStart}}' AND '{{dateEnd}}'
GROUP BY bucket
)
SELECT
hallucination_count.bucket AS timestamp,
CASE WHEN total_count.total = 0 THEN 0
ELSE hallucination_count.total / total_count.total
END AS hallucination_rate
FROM hallucination_count
JOIN total_count ON hallucination_count.bucket = total_count.bucket
ORDER BY hallucination_count.bucket DESC;Filtering and Grouping by Dimension
Filter to a specific dimension slice — for example, only production traffic:
SELECT
timestamp,
value
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'accuracy'
AND dimensions->>'environment' = 'production'
AND timestamp >= NOW() - INTERVAL '24 hours'
ORDER BY timestamp ASC;Group by a dimension — compare accuracy across model versions:
SELECT
time_bucket('1 hour', timestamp) AS hour,
dimensions->>'model_version' AS model_version,
AVG(value) AS avg_accuracy
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'accuracy'
AND timestamp >= NOW() - INTERVAL '7 days'
GROUP BY 1, 2
ORDER BY 1 ASC, 2 ASC;Gap Filling
Use time_bucket_gapfill to fill missing time intervals with zero or NULL when some buckets have no data — useful for continuous chart lines:
SELECT
time_bucket_gapfill(INTERVAL '1 hour', timestamp) AS bucket,
CASE WHEN SUM(value) IS NULL THEN 0 ELSE SUM(value) END AS total
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'inference_count'
AND timestamp BETWEEN '{{dateStart}}' AND '{{dateEnd}}'
GROUP BY bucket;Rolling Averages
Use a window function to smooth noisy metrics:
SELECT
timestamp,
value,
AVG(value) OVER (
ORDER BY timestamp
ROWS BETWEEN 11 PRECEDING AND CURRENT ROW
) AS rolling_1h_avg -- 12 × 5-minute buckets = 1 hour
FROM metrics_numeric_latest_version
WHERE model_id = '{{your-model-uuid}}'
AND metric_name = 'prediction_score_mean'
AND timestamp >= NOW() - INTERVAL '24 hours'
ORDER BY timestamp ASC;Updated about 22 hours ago