简化表格结构:

CREATE TABLE IF NOT EXISTS `hpa` (
  `id` bigint(15) NOT NULL auto_increment,
  `core` varchar(50) NOT NULL,
  `hostname` varchar(50) NOT NULL,
  `status` varchar(255) NOT NULL,
  `entered_date` int(11) NOT NULL,
  `active_date` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `hostname` (`hostname`),
  KEY `status` (`status`),
  KEY `entered_date` (`entered_date`),
  KEY `core` (`core`),
  KEY `active_date` (`active_date`)
)

为此,我有以下SQL查询,它简单地总计了具有已定义状态的所有记录。

SELECT core,COUNT(hostname) AS hostname_count, MAX(active_date) AS last_active
          FROM `hpa`
          WHERE 
          status != 'OK' AND status != 'Repaired'
          GROUP BY core
          ORDER BY core

此查询已简化为将INNER JOINS移除到不相关的数据和不应影响问题的额外列。

MAX(active_date)对于特定日期的所有记录都相同,应始终选择最近一天,或允许从NOW()开始偏移。 (这是一个UNIXTIME字段)

我想要两个计数:(状态!='确定'和状态!='修复')

和反...计数:(状态='确定'或状态='已修复')

并且第一个答案除以第二个答案,对于'percentage_dead'(可能在后期处理中一样快)

最近一天或抵消( - 昨天的86400等)。

表包含大约500k记录,每天增长大约5000个,因此单个SQL查询而不是循环将是非常好的..

我想一些创意的IF可以做到这一点。您的专业知识表示赞赏。

编辑:我愿意对今天的数据或偏移的数据使用不同的SQL查询。

编辑:查询工作,足够快,但我目前不能让用户对百分比列进行排序(从糟糕和良好计数派生的那一列)。这不是一个表演限制,但我允许他们对其他一切进行排序。 ORDER BY:

SELECT h1.core, MAX(h1.entered_date) AS last_active, 
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS good_host_count,  
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS bad_host_count 
FROM `hpa` h1 
LEFT OUTER JOIN `hpa` h2 ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date) 
WHERE h2.hostname IS NULL 
GROUP BY h1.core 
ORDER BY ( bad_host_count / ( bad_host_count + good_host_count ) ) DESC,h1.core

给我:     #1247 - 不支持引用'bad_host_count'(对组功能的引用)

编辑:解决了不同的部分。以下工作允许我 ORDER BY percentage_dead

SELECT c.core, c.last_active, 
SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END) AS good_host_count,  
SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) AS bad_host_count,
( SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) * 100/
( (SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END) )+(SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) ) ) ) AS percentage_dead
FROM `agent_cores` c 
LEFT JOIN `dead_agents` d ON c.core = d.core
WHERE d.active = 1
GROUP BY c.core
ORDER BY percentage_dead
有帮助吗?

解决方案

如果我理解,您希望在最后一次活动的日期计算OK与不是OK主机名的状态。对?然后应该按核心分组。

SELECT core, MAX(active_date)
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
  ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date)
WHERE h2.hostname IS NULL
GROUP BY core
ORDER BY core;

这是“每组最大n”的变体。我在StackOverflow上的SQL问题中看到了很多问题。

首先,我们只想选择每个主机名具有最新活动日期的行,我们可以通过对具有相同主机名和更大active_date的行执行外部联接来执行此操作。在我们找不到这样的匹配的地方,我们已经为每个给定的主机名提供了最新的行。

然后按核心分组并按状态计算行数。

这是今天日期的解决方案(假设未来没有行有active_date)。要在N天前将结果限制为行,您必须限制两个表。

SELECT core, MAX(active_date)
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
  ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date
  AND h2.active_date <= CURDATE() - INTERVAL 1 DAY)
WHERE h1.active_date <= CURDATE() - INTERVAL 1 DAY AND h2.hostname IS NULL
GROUP BY core
ORDER BY core; 

关于OK和损坏的主机名之间的比例,我建议只在PHP代码中计算它。 SQL不允许您在其他select-list表达式中引用列别名,因此您必须将上面的内容包装为子查询,并且在这种情况下它比它的值更复杂。


我忘了你说你正在使用UNIX时间戳。做这样的事情:

SELECT core, MAX(active_date)
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
  ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date
  AND h2.active_date <= UNIX_TIMESTAMP() - 86400)
WHERE h1.active_date <= UNIX_TIMESTAMP() - 86400 AND h2.hostname IS NULL
GROUP BY core
ORDER BY core; 
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top