1

我有 3 张桌子:

CREATE TABLE IF NOT EXISTS `disksinfo` (
  `idx` int(10) NOT NULL AUTO_INCREMENT,
  `hostinfo_idx` int(10) DEFAULT NULL,
  `id` char(30) DEFAULT NULL,
  `name` char(30) DEFAULT NULL,
  `size` bigint(20) DEFAULT NULL,
  `freespace` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`idx`)
)

CREATE TABLE IF NOT EXISTS `hostinfo` (
  `idx` int(10) NOT NULL AUTO_INCREMENT,
  `host_idx` int(11) DEFAULT NULL,
  `probetime` datetime DEFAULT NULL,
  `processor_load` tinyint(4) DEFAULT NULL,
  `memory_total` bigint(20) DEFAULT NULL,
  `memory_free` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`idx`)
)

CREATE TABLE IF NOT EXISTS `hosts` (
  `idx` int(10) NOT NULL AUTO_INCREMENT,
  `name` char(30) DEFAULT '0',
  PRIMARY KEY (`idx`)
) 

基本上,hosts 只是在 hostinfo 表中使用的固定主机名列表(hostinfo.host_idx = hosts.idx) hostinfo 是一个表,每隔几分钟就会用来自所有主机的数据填充一次,此外,对于每个 hostinfo 行,至少有一个 diskinfo 行被建造。每个磁盘信息行包含至少一个磁盘的信息(因此,对于某些主机,磁盘信息有 3-4 行)。磁盘信息.hostinfo_idx = 主机信息.idx。hostinfo.probetime 只是创建数据快照的时间。

我现在要执行的是为每个特定的不同主机(hostinfo.host_idx)选择最后一个主机信息(.probetime),同时加入有关磁盘(diskinfo 表)和主机名(主机表)的信息

我带来了这个:

SELECT hinfo.idx,
       hinfo.host_idx,
       hinfo.processor_load,
       hinfo.memory_total,
       hinfo.memory_free,
       hnames.idx,
       hnames.name,
       disks.hostinfo_idx,
       disks.id,
       disks.name,
       disks.size,
       disks.freespace,
       Max(hinfo.probetime)
FROM   systeminfo.hostinfo AS hinfo
       INNER JOIN systeminfo.hosts AS hnames
               ON hnames.idx = hinfo.host_idx
       INNER JOIN systeminfo.disksinfo AS disks
               ON disks.hostinfo_idx = hinfo.idx
GROUP  BY disks.id,
          hnames.name
ORDER  BY hnames.name,
          disks.id  

它似乎工作!但是,它是 100% 正确的吗?是最优的吗?感谢您的提示!

4

1 回答 1

3

这不是100%正确,不。

假设你有这张表:

x   |   y   |   z
-----------------
a       b       1
a       c       2
d       e       1
d       f       2

现在,当您仅按 x 分组时,行正在折叠,MySQL 从折叠的行中随机选择一行。所以你可能会得到

x   |   y   |   z
-----------------
a       b       2
d       e       2

或这个

x   |   y   |   z
-----------------
a       c       2
d       f       2

还是另一种组合,这个没有确定。每次触发查询时,您可能会得到不同的结果。由于该功能, 2in 列z始终存在,MAX()但您不一定会获得相应的行。

其他 RDBMS 实际上也会这样做,但大多数默认情况下都禁止这样做(在 MySQL 中也可以禁止)。你有两种可能来解决这个问题(实际上还有更多,但我会限制为两种)。

您可以将SELECT子句中所有未在聚合函数中使用的列SUM()MAX()其他任何内容也放入GROUP BY子句中,如下所示:

SELECT hinfo.idx,
       hinfo.host_idx,
       hinfo.processor_load,
       hinfo.memory_total,
       hinfo.memory_free,
       hnames.idx,
       hnames.name,
       disks.hostinfo_idx,
       disks.id,
       disks.name,
       disks.size,
       disks.freespace,
       Max(hinfo.probetime)
FROM   systeminfo.hostinfo AS hinfo
       INNER JOIN systeminfo.hosts AS hnames
               ON hnames.idx = hinfo.host_idx
       INNER JOIN systeminfo.disksinfo AS disks
               ON disks.hostinfo_idx = hinfo.idx
GROUP  BY 
       hinfo.idx,
       hinfo.host_idx,
       hinfo.processor_load,
       hinfo.memory_total,
       hinfo.memory_free,
       hnames.idx,
       hnames.name,
       disks.hostinfo_idx,
       disks.id,
       disks.name,
       disks.size,
       disks.freespace
ORDER  BY hnames.name,
          disks.id 

请注意,此查询可能会给您带来不同的结果!我只是关注这个问题,你可能会在你认为包含MAX(hinfo.probetime).

或者你像这样解决它(这会让你得到你想要的):

SELECT hinfo.idx,
       hinfo.host_idx,
       hinfo.processor_load,
       hinfo.memory_total,
       hinfo.memory_free,
       hnames.idx,
       hnames.name,
       disks.hostinfo_idx,
       disks.id,
       disks.name,
       disks.size,
       disks.freespace,
       hinfo.probetime
FROM   systeminfo.hostinfo AS hinfo
       INNER JOIN systeminfo.hosts AS hnames
               ON hnames.idx = hinfo.host_idx
       INNER JOIN systeminfo.disksinfo AS disks
               ON disks.hostinfo_idx = hinfo.idx
WHERE  hinfo.probetime = (SELECT MAX(probetime) FROM systeminfo.hostinfo AS hi
                                                INNER JOIN systeminfo.hosts AS hn
                                                ON hnames.idx = hinfo.host_idx
                                                INNER JOIN systeminfo.disksinfo AS d
                                                ON disks.hostinfo_idx = hinfo.idx
                          WHERE d.id = disks.id AND hn.name = hnames.name)
GROUP  BY disks.id,
          hnames.name
ORDER  BY hnames.name,
          disks.id

手册中还有一个很好的例子:The Rows Hold the Group-wise Maximum of a certain Column

于 2013-04-18T09:18:43.213 回答