Grafana Arc Datasource v1.1.0: The Update That Made 30-Day Queries Actually Work

#Arc#Grafana#datasource#plugin#performance#query-splitting#observability#release
Cover image for Grafana Arc Datasource v1.1.0: The Update That Made 30-Day Queries Actually Work

I'll be honest—v1.0.0 of the Grafana datasource worked great for short time ranges. Anything under 24 hours was fast, responsive, exactly what you'd expect. But the moment someone dragged the time picker to 7 days or 30 days, things fell apart. Dashboards timed out. Grafana froze. The "Cancel" button became your best friend.

We knew the datasource was talking to Arc correctly. Arc itself could handle these queries in seconds. The problem was somewhere in between—how the plugin processed and formatted the data before handing it to Grafana.

So we dug in. And what we found was a combination of two subtle bugs and a missing feature that, together, made large time-range queries essentially unusable.

The Numbers

Before we get into the details, here's what changed for a real-world 30-day query across 60 million rows and 900 compacted Parquet files:

MetricBefore (v1.0.0)After (v1.1.0)Improvement
Rows returned604,801+712850x fewer
Response size59MB+117KB500x smaller
Cold start (no split)TIMEOUT (>300s)29sworks now
Cold start (1d split)399s18s22x faster
Hot (cached)TIMEOUT14sworks now

That's not a marginal improvement. That's the difference between "this dashboard doesn't work" and "this dashboard loads in 14 seconds."

Bug #1: Null-Fill Bloat

When Grafana converts time-series data from "long" format (one row per data point) to "wide" format (one column per series), it needs to fill in gaps where some series have data and others don't. The LongToWide function has a FillMode parameter for this.

We were using FillModeNull—which sounds reasonable. "Fill gaps with nulls." But what it actually does is expand the time axis to per-second resolution and insert null rows for every missing second. An hourly query over 7 days doesn't have 168 rows—it has 604,800. Each one padded with nulls across every series column.

A 7-day dashboard that should return a few hundred rows was returning over half a million. Grafana was choking on 59MB of mostly-null JSON.

The fix: pass nil instead of FillModeNull. This tells LongToWide to only include timestamps that actually exist in the source data. Same visual result in the chart, 850x fewer rows.

Bug #2: date_trunc Nanosecond Residual

This one was sneakier. DuckDB stores timestamps with nanosecond precision (TIMESTAMP_NS). When you call date_trunc('hour', time) or time_bucket(INTERVAL '1 hour', time), DuckDB truncates to the hour—but retains sub-second residuals from the original nanosecond timestamp.

So two readings at 14:23:17.123456789 and 14:45:02.987654321 both get "truncated" to 14:00:00—but their nanosecond residuals differ. GROUP BY sees them as different values. Instead of one row per hour, you get one row per original reading.

The fix: a new $__timeGroup macro that uses epoch-based integer math to properly bucket timestamps, stripping nanosecond residuals entirely.

New: Query Splitting

Even with both bugs fixed, 30-day queries over hundreds of compacted Parquet files on S3 are inherently slow on first load—the files need to be downloaded before DuckDB can process them.

Query splitting breaks a large time range into smaller chunks and processes them in parallel. Four concurrent goroutines fetch and process sub-ranges simultaneously, overlapping S3 downloads with DuckDB query execution.

You configure it per-query in the editor with a dropdown: 1 hour, 6 hours, 12 hours, 1 day, 3 days, or 7 days. For a 30-day query with 1-day splitting, that's 30 parallel chunks instead of one monolithic query. Cold-start time dropped from 399 seconds to 18.

Auto-Migrate from Postgres/MySQL/MSSQL

Small but useful: when you switch a Grafana panel's datasource from Postgres, MySQL, or MSSQL to Arc, the query was disappearing. Those datasources store the query in a rawSql field. Arc expects sql. The query was there—just invisible.

Now the plugin detects rawSql on mount and migrates it to sql automatically. Switch your datasource and your query is still there.

Better Error Messages

v1.0.0 would show "query failed" for everything—timeouts, connection refused, malformed SQL, Arc-side errors. Now:

  • Arc error messages surface directly in the Grafana panel
  • Timeouts get a clear "query timed out" message with the duration
  • Connection refused tells you to check the Arc URL
  • EOF errors during streaming get a human-readable explanation

Small thing, but it saves a lot of time when debugging dashboard issues.

Get It

Download v1.1.0:

wget https://github.com/basekick-labs/grafana-arc-datasource/releases/download/v1.1.0/basekick-arc-datasource-1.1.0.zip
unzip basekick-arc-datasource-1.1.0.zip -d /var/lib/grafana/plugins/
systemctl restart grafana-server

Or if you're running Grafana in Kubernetes/OpenShift:

kubectl exec -it deployment/grafana -- /bin/sh
wget https://github.com/basekick-labs/grafana-arc-datasource/releases/download/v1.1.0/basekick-arc-datasource-1.1.0.zip
unzip basekick-arc-datasource-1.1.0.zip -d /var/lib/grafana/plugins/
exit
kubectl rollout restart deployment/grafana

Thanks to Khalid (https://github.com/Basekick-Labs/grafana-arc-datasource/pull/6) for the contribution.


Resources:

Questions? Reach out on Twitter or join our Discord.

Ready to handle billion-record workloads?

Deploy Arc in minutes. Own your data in Parquet. Use for analytics, observability, AI, IoT, or data warehousing.

Get Started ->