服务器详细信息(_D)

hostname category active
server1 small yes
server2 big yes

服务器统计信息服务器

hostname metric value lastupdated
server1 cpu 10 03:30:37
server1 ram 25 03:30:37
server1 disk 57 03:30:37
server2 cpu 23 03:30:37
server2 ram 55 03:30:37
server2 disk 33 03:30:37
server1 cpu 13 03:25:37
server1 ram 25 03:25:37
server1 disk 43 03:25:37
server2 cpu 83 03:25:37
server2 ram 95 03:25:37
server2 disk 63 03:25:37

结果应与上次更新的最新值类似

hostname category active cpu ram disk
server1 small yes 10 25 57
server2 big yes 23 55 33

我使用的是SQL Server数据库 我编写了以下查询,它给出了所需的输出

SELECT hd.hostname, hd.category, hd.active,
       (SELECT top 1 hs_cpu.value 
        FROM 服务器统计信息服务器 hs_cpu 
        WHERE hs_cpu.hostname = hd.hostname AND hs_cpu.metric = 'cpu' 
        ORDER BY hs_cpu.lastupdated DESC) AS cpu,
       (SELECT top 1 hs_ram.value 
        FROM 服务器统计信息服务器 hs_ram 
        WHERE hs_ram.hostname = hd.hostname AND hs_ram.metric = 'ram' 
        ORDER BY hs_ram.lastupdated DESC) AS ram,
       (SELECT top 1 hs_disk.value 
        FROM 服务器统计信息服务器 hs_disk 
        WHERE hs_disk.hostname = hd.hostname AND hs_disk.metric = 'disk' 
        ORDER BY hs_disk.lastupdated DESC) AS disk
FROM 服务器详细信息(_D) hd;

我们是否可以使用不带子查询的联接来优化此查询?

推荐答案

我不确定这是否真的是faster,但它是一种稍微更面向集合的方法,使用PIVOT并连接回细节:https://dbfiddle.uk/Ebw30T90

select *
from
(
    SELECT Latest.hostname, sd.category, sd.active, latest.metric, v.value
    FROM (
        SELECT hostname,metric, MAX(lastupdated) lastupdated
        FROM server_stat
        GROUP BY hostname,metric
    ) as Latest
    INNER JOIN server_stat v ON Latest.hostname = v.hostname AND Latest.metric = v.metric AND Latest.lastupdated = v.lastupdated
    INNER JOIN server_details sd on Latest.hostname = sd.hostname
) x
pivot
(
  max(value)
  for metric in([cpu],[ram],[disk])
) pvt
hostname category active cpu ram disk
server1 small yes 10 25 57
server2 big yes 23 55 33

这些数据的问题在于,聚合值(In this case 101)不是我们希望看到的值,而是我们想要的MAX(lastupdated)行中的value列,这使得使用PIVOT变得更加困难.

关键是先准备好要加到PIVOT的那一套,用GROUP BY代替TOP 1/LIMIT 1,然后再加回server_stat表得到value

SELECT Latest.hostname, sd.category, sd.active, latest.metric, v.value
FROM (
    SELECT hostname,metric, MAX(lastupdated) lastupdated
    FROM server_stat
    GROUP BY hostname,metric
) as Latest
INNER JOIN server_stat v ON Latest.hostname = v.hostname AND Latest.metric = v.metric AND Latest.lastupdated = v.lastupdated
INNER JOIN server_details sd on Latest.hostname = sd.hostname

一百零二

hostname category active metric value
server2 big yes ram 55
server2 big yes disk 33
server2 big yes cpu 23
server1 small yes ram 25
server1 small yes disk 57
server1 small yes cpu 10

Update: Thanks to Joel Coehoorn!

这是一件美好的事情;)我们可以将这种方法与this solution by Joel Coehoorn相结合,以消除自行联接以访问相关数据的GROUP BY.我真的不能 comments window queriesgroup by的性能,但用这种方式管理的代码要少得多.

select *
from
(
    -- Thanks Joel Coehoorn!
    SELECT distinct sd.hostname, sd.category, sd.active, metric
       , first_value(value) over (partition by sd.hostname, ss.metric 
                              order by lastupdated desc) value
    FROM Server_Details sd
    INNER JOIN Server_Stat ss on ss.hostname = sd.hostname
) x
pivot
(
  max(value)
  for metric in([cpu],[ram],[disk])
) pvt

小提琴更新:(查看最后一个查询)https://dbfiddle.uk/7D9lGpZI

Sql相关问答推荐

我可以将INSERT语句与SELECT一起使用来创建条件吗?

使用`lag()`获取上一个时间戳

删除MariaDB数据库中的JSON数据

有没有办法在每次计算每一行的数据时更新2个值?

提高写密集型表的查询性能

如何查找所提供日期范围的所有季度开始日期和结束日期

正在编写查询.我需要将订阅的时间段分为第一个订阅中包含的另一个订阅之前和之后的时间段

MS Access问题查询中的自定义字段

需要从键-值对数据中提取值

Postgres SQL查询从字符串中获取邮箱地址

如何使用聚合连接两个表

STContains、STIntersections和STWithin返回错误的地理结果

Postgresql - WHERE 中的 MAX 标准 - 初学者问题

YEAR 函数仍然不可SARGable 吗?

确定小数中使用的精度位数

MS ACCESS 错误插入 X(...) 从 A 联合 Select ... 从 B

SQL:如何从时间戳数据生成时间序列并计算不同事件类型的累计总和?

当没有任何行存在时,将一个表中的行插入到另一个表中的更好方法

SQL/Postgres:按日期和其他属性对相关性能进行分组

在 UTF 编码字符上应用 SQL LIKE 语句没有给出任何结果