我有一个监控应用程序,将指标存储在 MySQL DB 中,并使用 RRDtool 绘制时间序列图。DB 中的表有 3 列:timestamp、RRDKeyID 和 value,即。有一个数据表,如:
ts1 | user2 | some_value
ts1 | user4 | some_value
ts1 | user5 | some_value
ts1 | user7 | some_value
ts2 | user1 | some_value
ts2 | user2 | some_value
ts2 | user3 | some_value
ts2 | user5 | some_value
ts2 | user8 | some_value
ts3 | user3 | some_value
ts3 | user4 | some_value
ts3 | user5 | some_value
ts3 | user7 | some_value
...
数据以 1 分钟的间隔收集,用户(如您所知)自由连接到系统并生成指标,因此在任何给定时刻,系统中的用户数量都低于总数。用户总数约为 1k 并且在线总是有几百个,这意味着在 metric 表中有数百行具有相同的时间戳。当我生成图表时,我不想为每个用户显示该系列,因为由于画布尺寸太小、调色板有限、图例太长等原因,该图表不可读。这就是为什么我改为生成一个图表,其中只有按指标值排名前 10 位的用户单独显示,所有其他用户汇总到一个黑色区域。我就是这样做的:
:1: 我从表中获得前 10 名:
select RRDKeyID, avg(value) as avg
from metric_table
where ts between 't1' and 't2'
group by RRDKeyID
order by avg desc
limit 10
:2: 然后在 Perl 中生成 RRDtool 命令,该命令绘制每个用户 (RRDKeyID) 都有自己的 DEF 的图形,但只有 SQL 查询结果中的用户 DEF 被直接绘制,其余的都被聚合:
CDEF:others=0,user11,ADDNAN,user12,ADDNAN,user13,ADDNAN,...,userN
然后"AREA:others#000000:OTHERS:STACK"
显示在图表上。
现在我正在开发应用程序的下一个版本,由于 DB 模式的变化,RRDtool 将被 D3.js 取代,所以我需要另一种方法来生成我的 top10 + 其他人的数据。我不想将原始数据发送到客户端并在他们这边进行处理,因为数据集可能非常大,处理可能需要很多时间和 CPU,所以我宁愿在服务器端进行。我怀疑有可能以以下格式获得我想要的结果:
ts | user | value
------+--------+-------
t1 | u1 | v
t1+1 | u1 | v
t1+2 | u1 | v
...
t2 | u1 | v
t1 | u2 | v
...
t2 | u2 | v
t1 | u3 | v
...
t2 | u3 | v
...
...
t1 | u10 | v
...
t2 | u10 | v
t1 | others | v
...
t2 | others | v
一次性(顺序不重要)使用嵌套查询,其中有一个子查询在给定的时间范围内选择用户名(RRDKeyIDs)和 avg(值),然后顶部查询打印用户名的结果,如果他们是在子查询结果中找到或以其他方式将它们添加到其他人。我不知道如何用 SQL 表达这个想法,所以如果有人能提出解决方案,我将不胜感激。