2015-09-04 73 views
2

我为我们的用户PC创建了一个简单的统计工具。它每5分钟记录我们所有电脑的状态。而一个前端给我一个用法图: enter image description here优化SQL子查询统计

现在随着数据越来越多,SQL查询越来越慢,我正在寻找一种方法来优化它。

这是结构。正如你所看到的,表“使用”载约6万条记录,并使用MySQL的InnoDB:

CREATE TABLE IF NOT EXISTS `usage` (
`id` int(11) unsigned NOT NULL, 
    `host_id` int(10) unsigned NOT NULL, 
    `time` int(10) unsigned NOT NULL, 
    `state` enum('LinuxTU','LinuxExt','View','Browser','Idle','Offline') CHARACTER SET latin1 NOT NULL DEFAULT 'Offline' 
) ENGINE=InnoDB AUTO_INCREMENT=5963366 DEFAULT CHARSET=utf8; 

ALTER TABLE `usage` 
ADD PRIMARY KEY (`id`), ADD KEY `host_id` (`host_id`), ADD KEY `time` (`time`); 

ALTER TABLE `usage` 
MODIFY `id` int(11) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5963366; 

下面的查询需要大约7秒执行。这是将数据提供给屏幕截图的查询。

/* create pivot table */ 
SELECT `time`, 
    SUM(IF(state='LinuxTU', statecount, 0)) AS LinuxTU, 
    SUM(IF(state='LinuxExt', statecount, 0)) AS LinuxExt, 
    SUM(IF(state='View', statecount, 0)) AS View, 
    SUM(IF(state='Browser', statecount, 0)) AS Browser 
FROM (
    /* get data from last 24h grouped by state */ 
    SELECT `time`, `state`, COUNT(`state`) statecount 
    FROM `usage` u 
    /* group by time to get every 5 minutes 
     group by state to get the state counter */ 
    GROUP BY `time`, `state` 
    HAVING `time` > 1441271078 AND `time` < 1441357478 
) AS s 
GROUP BY `time` 
ORDER BY `time` ASC 

我不知道如何优化它。有什么我错过了吗?或者我需要重新组织结构?任何提示?

回答

0

我觉得你的问题是因为子查询的指标都没有了对最后

GROUP BY `time` 
ORDER BY `time` ASC 

。所以,你应该找到一种方法来消除这种情况。

您是否也可以选择使用编程语言进行一些处理?只需在内部选择+外部选择无变量的变量,并添加顺序,然后在编程语言中进行处理。

或者你必须在查询中写这个吗?

+0

我可以通过改变从一个ENUM字段的表到多个国家领域消除支点查询(如LinuxTU = 0,LinuxExt = 1)。但是我认为多个领域使得它变得僵化和可能更为紧张(例如:LinuxTU = 1和LinuxExt = 1)。实际上前端使用这些数据。所以每个查询都会输出所需的数据。 – Michael

0

我发现了瓶颈。问题是内部查询。 HAVING似乎比WHERE慢得多。于是,我尝试了一些不同的查询,现在我得到这样的结果:

需要7秒时:

SELECT `time`, `state`, COUNT(`state`) statecount 
FROM `usage` u 
GROUP BY `time`, `state` 
HAVING `time` > 1441271078 AND `time` < 1441357478 

用0.1秒时:

SELECT `time`, `state`, COUNT(`state`) `statecount` 
FROM `usage` u 
WHERE `time` > 1441271078 AND `time` < 1441357478 
GROUP BY `time`, `state` 

,给我相同的结果。前端现在快得多。

2

除了移动time比较成where条款,你可以摆脱完全的子查询:

/* create pivot table */ 
SELECT `time`, 
     SUM(state = 'LinuxTU') AS LinuxTU, 
     SUM(state = 'LinuxExt') AS LinuxExt, 
     SUM(state = 'View') AS View, 
     SUM(state = 'Browser') AS Browser 
FROM usage u 
WHERE `time` > 1441271078 AND `time` < 1441357478 
GROUP BY `time` 
ORDER BY `time` ASC;