In Grafana, data coming from many sources includes sparse labels โ meaning some series have label keys that others do not.
This is common in systems like Prometheus, OpenTelemetry, or SQL queries with GROUP BY.
However, traditional long formats (like time_series_long
or numeric_long
) do not preserve label sparsity correctly, leading to broken behaviors in visualization, alerts, and expressions.
When converting from Wide or Multi to a Long format:
- All observed label keys are turned into string fields
- Rows where a label is not present get filled with
""
,"unknown"
, or another default
This means:
You can no longer distinguish between
"label" not present
and"label" = ''
(empty string)
Before:
cpu{host="a"}
cpu{host="a",int="eth0"}
After flattening:
cpu{host="a",int=""}
cpu{host="a",int="eth0"}
Impact:
- The panel renders 2 series instead of 1 (unexpectedly)
- Legend shows
int=""
which user never wrote - Confusing UI and data interpretation
Flattened rows cause:
- Phantom series
- Duplicate alert instances (one per padded label set)
- Broken alert silencing due to label mismatch
Example:
Alert for cpu{host="a"} fires twice:
- cpu{host="a",int=""}
- cpu{host="a",int="eth0"}
Transformations like Group By or Reduce rely on exact label identity.
Flattened labels:
- Cause unrelated series to group together
- Or cause real series to fragment into multiple groups
Example:
GROUP BY host,int
Includes series with "int" = ""
that shouldnโt be there.
Before: Only real label sets are shown.
After flattening:
- Legend shows
int=""
,int="eth0"
, etc. - Panel becomes noisy
- User loses confidence in data or query logic
SQL expects well-formed rows. When flattening inserts defaults like ""
:
- SQL results include phantom rows
- GROUP BY logic fails silently
- Alert expressions or formulas break
These formats:
- Keep label keys as columns (like Long)
- Use
null
when a label was not set - Include
__metric__
field to preserve metric identity - Support round-trip back to Wide/Multi
Example:
| __metric__ | host | int | value |
|------------|------|-------|--------|
| cpu | a | null | 1.0
| cpu | a | eth0 | 2.0
Without *_full_long |
With *_full_long |
---|---|
โ Mystery series in legend | โ Only true series appear |
โ Duplicate alerts | โ One alert per real series |
โ Broken reduce / group transforms | โ Accurate results |
โ Confusing SQL results | โ Clean, expected rows |
โ Phantom data in UI | โ Sparse labels preserved as-is |
Label sparsity is a fundamental property of dimensional time series data.
If not handled correctly, it silently breaks behavior in:
- Visualizations
- Alerts
- SQL expressions
- Transformations
- Legends and query interfaces
The *_full_long
formats solve this problem with:
- Explicit metric identity
- Null-aware label handling
- Row-normalized, SQL-friendly structure
This ensures correctness, clarity, and round-trip safety throughout the Grafana pipeline.