I have a solution that runs reasonably well and that addresses the scaling problem for the number queries and the number of points per history. To deal with the number of queries we construct a temporary table where each column contains the time history for a host. Each column requires a single query to populate it. The table would be constructed with the following subqueries:
FROM
(SELECT DISTINCT time FROM metric) t
LEFT JOIN (SELECT time,metric FROM metric WHERE host=1) t1 ON t.time=t1.time
LEFT JOIN (SELECT time,metric FROM metric WHERE host=2) t2 ON t.time=t2.time
etc.
To address the time point scaling we use the Grafana $__interval
variable and $__timeGroupAlias
macro:
SELECT
$__timeGroupAlias(t.time, $__interval),
avg(t1.metric) AS host1,
avg(t2.metric) AS host2,
etc.
FROM <use-subquery-from-above>
WHERE
$__timeFilter(t.time)
GROUP BY 1
ORDER BY 1
To allow the user to manage the dashboard we will use 3 variables, one to present a drop down with host names and the other two chained from the first to fill in the SELECT and FROM subqueries. The drop down would be created with a query variable called hosts
with the following definition:
SELECT name FROM host
To define the subqueries in the SELECT we create a variable called columns
with the following:
SELECT string_agg(format('avg(t%s.cost) AS "%s"', id, name), ',')
FROM host
WHERE name IN ($hosts)
Then the subqueries in the FROM clause would be from a variable called tables
with the following definition:
SELECT '(SELECT DISTINCT time FROM metric) t ' || string_agg(format('LEFT JOIN (SELECT time,metric FROM metric WHERE host=%s) t%1$s ON t.time=t%1$s.time', id), ' ')
FROM host
WHERE name IN ($hosts)
Finally to put it all together the query with variables looks like:
SELECT
$__timeGroupAlias(t.time, $__interval),
${columns}
FROM ${tables}
WHERE
$__timeFilter(t.time)
GROUP BY 1
ORDER BY 1